This document aims at exploring the dataset of 4 individuals in 2018. For that purpose, we need first to load the ontodive package to load data.
For convenience, we aggregate all 4 individuals into one dataset.
Some explanatory plots
Missing values
# build dataset to check for missing values
dataPlot <- melt(data_2018[, .(.id, is.na(.SD)), .SDcol = -c(
".id",
"divenumber",
"divetype",
"date",
"phase",
"lat",
"lon"
)])
# add the id of rows
dataPlot[, id_row := c(1:.N), by = c("variable", ".id")]
# plot
ggplot(dataPlot, aes(x = variable, y = id_row, fill = value)) +
geom_tile() +
labs(x = "Attributes", y = "Rows") +
scale_fill_manual(
values = c("white", "black"),
labels = c("Real", "Missing")
) +
facet_wrap(.id ~ ., scales = "free_y") +
theme_jjo() +
theme(
legend.position = "top",
axis.text.x = element_text(angle = 45, hjust = 1),
legend.key = element_rect(colour = "black")
)
So far so good, only few variables seems to have missing values:
# table with percent
table_inter <- data_2018[, lapply(.SD, function(x) {
round(length(x[is.na(x)]) * 100 / length(x), 1)
}), .SDcol = -c(
".id",
"divenumber",
"divetype",
"date",
"phase",
"lat",
"lon"
)]
# find which are different from 0
cond_inter <- sapply(table_inter, function(x) {
x == 0
})
# display the percentages that are over 0
table_inter[, which(cond_inter) := NULL] %>%
sable(caption = "Percentage of missing values per columns having missing values!") %>%
scroll_box(width = "100%")
Table 3: Percentage of missing values per columns having missing values!
|
driftrate
|
lightatsurf
|
dist_dep
|
ssh
|
psu
|
vel
|
temp
|
bathy
|
|
0.5
|
26.3
|
35.1
|
35.1
|
35.1
|
35.1
|
35.1
|
35.1
|
Outliers
Ok, let’s have a look at all the data. But first, we have to remove outliers. Some of them are quiet easy to spot looking at the distribution of dive duration:
Before
ggplot(
rbind(
copy(data_2018)[, state := "Before"],
copy(data_2018)[dduration < 3000, ][, state := "After"]
) %>%
.[, state := factor(state, levels = c("Before", "After"))],
aes(x = dduration, fill = .id)
) +
geom_histogram(show.legend = FALSE) +
geom_vline(xintercept = 3000, linetype = "longdash") +
facet_grid2(state ~ .id,
scales = "free",
independent = "x"
) +
labs(y = "# of dives", x = "Dive duration (s)") +
theme_jjo()
It seems much better, so let’s remove any rows with dduration > 3000 sec.
# filter data
data_2018_filter <- data_2018[dduration < 3000, ]
# nbrow removed
data_2018[dduration >= 3000, .(nb_row_removed = .N), by = .id] %>%
sable(caption = "# of rows removed by 2018-individuals")
Table 4: # of rows removed by 2018-individuals
|
.id
|
nb_row_removed
|
|
ind_2018070
|
3
|
|
ind_2018072
|
1
|
|
ind_2018074
|
33
|
Check day and night
Light levels
# let's first average `lightatsurf` by individuals, day since departure and hour
dataPlot <- data_2018[, .(lightatsurf = median(lightatsurf)),
by = .(.id, day_departure, date = as.Date(date), hour = hour(date))
]
# display the result
ggplot(dataPlot, aes(x = day_departure, y = hour, fill = lightatsurf)) +
geom_tile() +
facet_grid(.id ~ .) +
theme_jjo() +
labs(
x = "# of days since departure",
y = "Hour",
fill = "Light level at the surface"
) +
theme(legend.position = c("bottom"))
Day and night detection
# let's first average `lightatsurf` by individuals, day since departure and hour
dataPlot <- data_2018[, .(lightatsurf = median(lightatsurf)),
by = .(.id,
day_departure,
date = as.Date(date),
hour = hour(date),
phase
)
]
# display the result
ggplot(dataPlot, aes(x = day_departure, y = hour, fill = phase)) +
geom_tile() +
facet_grid(.id ~ .) +
theme_jjo() +
labs(
x = "# of days since departure",
y = "Hour",
fill = "Day time and night time as detected by the `cal_phase_day` function"
) +
theme(legend.position = c("bottom"))
All Variables
names_display <- names(data_2018_filter[, -c(
".id",
"date",
"divenumber",
"divetype",
"day_departure",
"phase",
"lat",
"lon",
"dist_dep",
"sp"
)])
# calulate the median of driftrate for each day
median_driftrate <- data_2018[divetype == "2: drift",
.(driftrate = quantile(driftrate, 0.5)),
by = .(date = as.Date(date), .id)
]
# let's identity when the smooth changes sign
changes_driftrate <- median_driftrate %>%
.[, .(
y_smooth = predict(loess(driftrate ~ as.numeric(date), span = 0.25)),
date
), by = .id] %>%
.[c(FALSE, diff(sign(y_smooth)) != 0), ]
for (i in names_display) {
cat("####", i, "{.unlisted .unnumbered} \n")
if (i == "driftrate") {
print(
ggplot(
data = melt(data_2018_filter[, .(.id, date, get(i), divetype)],
id.vars = c(".id", "date", "divetype")
),
aes(
x = as.Date(date),
y = value,
col = divetype
)
) +
geom_point(
alpha = 1 / 10,
size = .5
) +
geom_vline(
data = changes_driftrate,
aes(xintercept = date),
linetype = 2
) +
facet_wrap(. ~ .id, scales = "free") +
scale_x_date(date_labels = "%m/%Y") +
labs(x = "Date", y = "Drift Rate 'm/s", col = "Dive Type") +
theme_jjo() +
theme(
axis.text.x = element_text(angle = 45, hjust = 1),
legend.position = "bottom"
) +
guides(colour = guide_legend(override.aes = list(
size = 7,
alpha = 1
)))
)
} else {
print(
ggplot(
data = melt(data_2018_filter[, .(.id, date, get(i))],
id.vars = c(".id", "date")
),
aes(
x = as.Date(date),
y = value,
col = .id
)
) +
geom_point(
show.legend = FALSE,
alpha = 1 / 10,
size = .5
) +
geom_vline(
data = changes_driftrate,
aes(xintercept = date),
linetype = 2
) +
geom_vline(data = dataVline, aes(xintercept = as.Date(date)), colour = "black", linetype = 2) +
facet_wrap(. ~ .id, scales = "free") +
scale_x_date(date_labels = "%m/%Y") +
labs(x = "Date", y = i) +
theme_jjo() +
theme(axis.text.x = element_text(angle = 45, hjust = 1))
)
}
cat("\n \n")
}
The vertical dashed lines represent changes in buoyancy (see vignette("buoyancy_detect") for more information)
maxdepth

dduration

botttime

desctime

descrate

asctime

ascrate

pdi

dwigglesdesc

dwigglesbott

dwigglesasc

totvertdistbot

driftrate

lightatsurf

ssh

psu

vel

temp

bathy

Few questions, that I should look into it:
- is the bimodal distribution of
dduration, desctime due to nycthemeral migration?
- is the bimodal distribution of
descrate (especially for ind2018070 and ind_2018072) due to drift dive?
- is
lightatbott could be used to identify bioluminescence, cause it seems there is a lot going on at the bottom?
- are the variations observed for
lightatsurf is due to moon cycle?
- not sure why is there a bimodal distribution of
tempatbott!
driftrate that one is awesome! Thanks to divetype we can clearly see a pattern of how driftrate (and so buoyancy) change according time.
# same plot with a colored for the phase of the day
for (i in names_display) {
cat("####", i, "{-} \n")
print(
ggplot(
data = melt(data_2018_filter[, .(.id, date, get(i), phase)],
id.vars = c(
".id",
"date",
"phase"
)
),
aes(
x = as.Date(date),
y = value,
col = phase
)
) +
geom_point(
alpha = 1 / 10,
size = .5
) +
geom_vline(
data = changes_driftrate,
aes(xintercept = date),
linetype = 2
) +
facet_wrap(. ~ .id, scales = "free") +
scale_x_date(date_labels = "%m/%Y") +
labs(x = "Date", y = i) +
theme_jjo() +
theme(
axis.text.x = element_text(angle = 45, hjust = 1),
legend.position = "bottom"
) +
guides(colour = guide_legend(override.aes = list(
size = 7,
alpha = 1
)))
)
cat("\n \n")
}
The vertical dashed lines represent changes in buoyancy (see vignette("buoyancy_detect") for more information)
maxdepth

dduration

botttime

desctime

descrate

asctime

ascrate

pdi

dwigglesdesc

dwigglesbott

dwigglesasc

totvertdistbot

driftrate

lightatsurf

ssh

psu

vel

temp

bathy

All Variables during the first month
for (i in names_display) {
cat("####", i, "{.unlisted .unnumbered} \n")
print(
ggplot(
data = melt(
data_2018_filter[
day_departure < 32,
.(.id, day_departure, get(i))
],
id.vars = c(".id", "day_departure")
),
aes(
x = day_departure,
y = value,
color = .id,
group = day_departure
)
) +
geom_boxplot(
show.legend = FALSE,
alpha = 1 / 10,
size = .5
) +
facet_wrap(. ~ .id, scales = "free") +
labs(x = "# days since departure", y = i) +
theme_jjo()
)
cat("\n \n")
}
maxdepth

dduration

botttime

desctime

descrate

asctime

ascrate

pdi

dwigglesdesc

dwigglesbott

dwigglesasc

totvertdistbot

driftrate

lightatsurf

ssh

psu

vel

temp

bathy

for (i in names_display) {
cat("####", i, "{.unlisted .unnumbered} \n")
print(
ggplot(
data = melt(
data_2018_filter[
day_departure < 32,
.(.id, day_departure, get(i), phase)
],
id.vars = c(".id", "day_departure", "phase")
),
aes(
x = day_departure,
y = value,
color = phase,
group = interaction(day_departure, phase),
)
) +
geom_boxplot(
alpha = 1 / 10,
size = .5
) +
facet_wrap(. ~ .id, scales = "free") +
labs(x = "# days since departure", y = i) +
theme_jjo() +
theme(legend.position = "bottom")
)
cat("\n \n")
}
maxdepth

dduration

botttime

desctime

descrate

asctime

ascrate

pdi

dwigglesdesc

dwigglesbott

dwigglesasc

totvertdistbot

driftrate

lightatsurf

ssh

psu

vel

temp

bathy

Correlation
Can we find nice correlation?
# compute correlation
corr_2018 <- round(cor(data_2018_filter[, names_display, with = F],
use = "pairwise.complete.obs"
), 1)
# replace NA value by 0
corr_2018[is.na(corr_2018)] <- 0
# compute p_values
corr_p_2018 <- cor_pmat(data_2018_filter[, names_display, with = F])
# replace NA value by 0
corr_p_2018[is.na(corr_p_2018)] <- 1
# display
ggcorrplot(
corr_2018,
p.mat = corr_p_2018,
hc.order = TRUE,
method = "circle",
type = "lower",
ggtheme = theme_jjo(),
sig.level = 0.05,
colors = c("#00AFBB", "#E7B800", "#FC4E07")
)
Another way to see it:
# flatten correlation matrix
cor_result_2018 <- flat_cor_mat(corr_2018, corr_p_2018)
# keep only the one above .7
cor_result_2018[cor >= .7, ][order(-abs(cor))] %>%
sable(caption = "Pairwise correlation above 0.75 and associated p-values")
Table 5: Pairwise correlation above 0.75 and associated p-values
|
row
|
column
|
cor
|
p
|
|
maxdepth
|
asctime
|
0.8
|
0
|
|
maxdepth
|
dduration
|
0.7
|
0
|
|
maxdepth
|
desctime
|
0.7
|
0
|
|
dduration
|
desctime
|
0.7
|
0
|
|
dduration
|
asctime
|
0.7
|
0
|
I guess nothing unexpected here ;)
Dive Type
# dataset to plot proportional area plot
dataPlot <- data_2018_filter %>%
.[, .(sum_id_days = .N), by = .(.id, day_departure, divetype)] %>%
.[, prop := sum_id_days / sum(sum_id_days), by = .(.id, day_departure)]
# area plot
ggplot(dataPlot, aes(
x = as.numeric(day_departure),
y = prop,
fill = as.character(divetype)
)) +
geom_area(alpha = 0.6, size = 1, position = "stack", stat = "identity") +
facet_wrap(.id ~ ., scales = "free") +
scale_y_continuous(labels = scales::percent) +
theme_jjo() +
theme(legend.position = "bottom") +
labs(
x = "# of days since departure",
y = "Proportion of dives",
fill = "Dive types"
)
Dive duration vs. Maximum depth
Colored by ID
# plot
ggplot(data = data_2018_filter, aes(y = dduration, x = maxdepth, col = .id)) +
geom_point(size = .5, alpha = .1, show.legend = FALSE) +
facet_wrap(.id ~ .) +
labs(x = "Maximum depth (m)", y = "Dive duration (s)") +
theme_jjo()
Colored by Dive Type
# plot
ggplot(data = data_2018_filter, aes(
y = dduration,
x = maxdepth,
col = divetype
)) +
geom_point(size = .5, alpha = .1) +
facet_wrap(.id ~ .) +
guides(colour = guide_legend(override.aes = list(size = 5, alpha = 1))) +
labs(x = "Maximum depth (m)", y = "Dive duration (s)") +
theme_jjo() +
theme(legend.position = "bottom")
Colored by # days since departure
# plot
ggplot(
data = data_2018_filter[, prop_track := (day_departure * 100) / max(day_departure), by = .id],
aes(y = dduration, x = maxdepth, col = prop_track)
) +
geom_point(size = .5, alpha = .1) +
facet_wrap(.id ~ .) +
labs(
x = "Maximum depth (m)",
y = "Dive duration (s)",
col = "Proportion of completed track (%)"
) +
scale_color_continuous(type = "viridis") +
theme_jjo() +
theme(legend.position = "bottom")
Colored by phases of day
# plot
ggplot(data = data_2018_filter, aes(y = dduration, x = maxdepth, col = phase)) +
geom_point(size = .5, alpha = .1) +
facet_wrap(.id ~ .) +
guides(colour = guide_legend(override.aes = list(size = 5, alpha = 1))) +
labs(
x = "Maximum depth (m)",
y = "Dive duration (s)",
col = "Phases of the day"
) +
theme_jjo() +
theme(legend.position = "bottom")
There seems to be a patch for high depths (especially visible for ind2018070), but I don’t know what it could be linked to…
Drift Rate
In the following graphs:
driftrate is calculated using only divetype == "2: drift"
- whereas all the others variables are calculated all dives considered
# build dataset
dataPlot <- data_2018_filter[divetype == "2: drift",
# median drift rate for drift dive
.(driftrate = median(driftrate, na.rm = T)),
by = .(.id, day_departure)
] %>%
.[
data_2018_filter[,
.(
# median dive duration all dives considered
dduration = median(dduration, na.rm = T),
# median max depth all dives considered
maxdepth = median(maxdepth, na.rm = T),
# median bottom dives all dives considered
botttime = median(botttime, na.rm = T)
),
by = .(.id, day_departure)
],
on = c(".id", "day_departure")
]
# plot
ggplot(dataPlot, aes(x = botttime, y = driftrate, col = .id)) +
geom_point(size = .5, alpha = .5) +
geom_smooth(method = "lm") +
guides(color = "none") +
facet_wrap(.id ~ .) +
scale_x_continuous(limits = c(0, 700)) +
labs(
x = "Daily median Bottom time (s)",
y = "Daily median drift rate (m.s-1)"
) +
theme_jjo()
# plot
ggplot(dataPlot, aes(x = maxdepth, y = driftrate, col = .id)) +
geom_point(size = .5, alpha = .5) +
geom_smooth(method = "lm") +
guides(color = "none") +
facet_wrap(.id ~ .) +
labs(
x = "Daily median Maximum depth (m)",
y = "Daily median drift rate (m.s-1)"
) +
theme_jjo()
# plot
ggplot(dataPlot, aes(x = dduration, y = driftrate, col = .id)) +
geom_point(size = .5, alpha = .5) +
geom_smooth(method = "lm") +
guides(color = "none") +
facet_wrap(.id ~ .) +
labs(
x = "Daily median Dive duration (s)",
y = "Daily median drift rate (m.s-1)"
) +
theme_jjo()
Behavioral Aerobic Dive Limit (bADL)
# dive duration vs pdi by days
ggplot(data = data_2018_filter[pdi < 300, ], aes(
x = dduration,
y = pdi,
color = .id,
group = dduration,
fill = "none"
)) +
geom_boxplot(show.legend = FALSE, outlier.alpha = 0.05, alpha = 0) +
labs(x = "Dive duration (s)", y = "Post-dive duration (s)") +
facet_wrap(. ~ .id, scales = "free_x") +
theme_jjo()
# dive duration vs pdi by days
ggplot(data = data_2018_filter[pdi < 300, ], aes(
x = dduration,
y = pdi,
color = .id
)) +
geom_point(show.legend = FALSE, alpha = 0.05) +
geom_smooth(
method = "gam",
show.legend = FALSE,
col = "black",
linetype = "dashed"
) +
labs(x = "Dive duration (s)", y = "Post-dive duration (s)") +
facet_wrap(. ~ .id, scales = "free_x") +
theme_jjo()
# dive duration vs pdi by days
ggplot(
data = data_2018_filter[pdi < 300, .(.id, pdi_ratio = pdi / dduration, day_departure)],
aes(
x = day_departure,
y = pdi_ratio,
color = .id,
group = day_departure,
fill = "none"
)
) +
geom_boxplot(
show.legend = FALSE,
outlier.alpha = 0.05,
alpha = 0
) +
labs(x = "# days since departure", y = "Post-dive / Dive duration ratio") +
facet_wrap(. ~ .id, scales = "free_x") +
# zoom
coord_cartesian(ylim = c(0, 0.4)) +
theme_jjo()
Based on Shero et al. (2018), we decided to look at the bADL as the 95th percentile of dive duration each day, for those with \(n \geq 50\). This threshold was chosen following this figure:
ggplot(
data_2018_filter[, .(nb_dives = .N),
by = .(.id, day_departure)
],
aes(x = nb_dives, fill = .id)
) +
geom_histogram(show.legend = FALSE) +
geom_vline(xintercept = 50, linetype = "dashed") +
facet_grid(. ~ .id) +
labs(y = "# of days", x = "# of dives per day") +
theme_jjo()
# select day that have at least 50 dives
days_to_keep <- data_2018_filter[,
.(nb_dives = .N),
by = .(.id, day_departure)
] %>%
.[nb_dives >= 50, ]
# keep only those days
data_2018_filter_complete_day <- merge(data_2018_filter,
days_to_keep,
by = c(".id", "day_departure")
)
# data plot
dataPlot <- data_2018_filter_complete_day[divetype == "1: foraging",
.(badl = quantile(dduration, 0.95)),
by = .(.id, day_departure)
]
# combine two datasets to be able to use a second axis
# https://stackoverflow.com/questions/49185583/two-y-axes-with-different-scales-for-two-datasets-in-ggplot2
dataMegaPlot <- rbind(
data_2018_filter_complete_day[divetype == "2: drift"] %>%
.[, .(
w = .id,
y = driftrate,
x = day_departure,
z = "second_plot"
)],
dataPlot[, .(
w = .id,
# tricky one
y = (badl / 1000) - 1,
x = day_departure,
z = "first_plot"
)]
)
# plot
ggplot() +
geom_point(
data = dataMegaPlot[z == "second_plot", ],
aes(x = x, y = y),
alpha = 1 / 10,
size = 0.5,
color = "grey40",
show.legend = FALSE
) +
geom_path(
data = dataMegaPlot[z == "first_plot", ],
aes(x = x, y = y, color = w),
show.legend = FALSE
) +
scale_y_continuous(
# Features of the first axis
name = "Drift rate (m/s)",
# Add a second axis and specify its features
sec.axis = sec_axis(~ (. * 1000) + 1000,
name = "Behavioral Aerobic Dive Limit (s)"
)
) +
labs(x = "# days since departure") +
facet_wrap(w ~ .) +
theme_jjo()
Looking at this graph, I want to believe that there is some kind of relationship between the bADL as defined by Shero et al. (2018) and the drift rate (and so buyoancy).
# get badl
dataplot_1 <- data_2018_filter_complete_day[,
.(badl = quantile(dduration, 0.95)),
by = .(.id, day_departure)
]
# get driftrate
dataplot_2 <- data_2018_filter_complete_day[divetype == "2: drift",
.(driftrate = median(driftrate)),
by = .(.id, day_departure)
]
# merge
dataPlot <- merge(dataplot_1,
dataplot_2,
by = c(".id", "day_departure"),
all = TRUE
)
# plot
ggplot(data = dataPlot, aes(x = badl, y = driftrate, col = .id)) +
geom_point(show.legend = FALSE) +
facet_wrap(.id ~ ., scales = "free") +
theme_jjo()

ind_2018070
# ind_2018070
plot_ly(
x = dataPlot[.id == "ind_2018070", badl],
y = dataPlot[.id == "ind_2018070", day_departure],
z = dataPlot[.id == "ind_2018070", driftrate],
type = "scatter3d",
mode = "markers",
marker = list(size = 2),
color = dataPlot[.id == "ind_2018070", day_departure]
) %>%
layout(scene = list(
xaxis = list(title = "Behavioral ADL"),
yaxis = list(title = "# days since departure"),
zaxis = list(title = "Drift rate (m/s)")
))
ind_2018072
# ind_2018072
plot_ly(
x = dataPlot[.id == "ind_2018072", badl],
y = dataPlot[.id == "ind_2018072", day_departure],
z = dataPlot[.id == "ind_2018072", driftrate],
type = "scatter3d",
mode = "markers",
marker = list(size = 2),
color = dataPlot[.id == "ind_2018072", day_departure]
) %>%
layout(scene = list(
xaxis = list(title = "Behavioral ADL"),
yaxis = list(title = "# days since departure"),
zaxis = list(title = "Drift rate (m/s)")
))
ind_2018074
# ind_2018074
plot_ly(
x = dataPlot[.id == "ind_2018074", badl],
y = dataPlot[.id == "ind_2018074", day_departure],
z = dataPlot[.id == "ind_2018074", driftrate],
type = "scatter3d",
mode = "markers",
marker = list(size = 2),
color = dataPlot[.id == "ind_2018074", day_departure]
) %>%
layout(scene = list(
xaxis = list(title = "Behavioral ADL"),
yaxis = list(title = "# days since departure"),
zaxis = list(title = "Drift rate (m/s)")
))
ind_2018072
# ind_2018080
plot_ly(
x = dataPlot[.id == "ind_2018080", badl],
y = dataPlot[.id == "ind_2018080", day_departure],
z = dataPlot[.id == "ind_2018080", driftrate],
type = "scatter3d",
mode = "markers",
marker = list(size = 2),
color = dataPlot[.id == "ind_2018080", day_departure]
) %>%
layout(scene = list(
xaxis = list(title = "Behavioral ADL"),
yaxis = list(title = "# days since departure"),
zaxis = list(title = "Drift rate (m/s)")
))
LS0tCnRpdGxlOiAiRGF0YSBFeHBsb3JhdGlvbiBORVMgKDEvMikgLSAyMDE4IgphdXRob3I6ICJKb2ZmcmV5IEpPVU1BQSIKZGF0ZTogImByIGludmlzaWJsZShTeXMuc2V0bG9jYWxlKGxvY2FsZSA9ICdDJykpOyBmb3JtYXQoU3lzLkRhdGUoKSwgZm9ybWF0ID0gJyVCICVkLCAlWScpYCIKb3V0cHV0OgogIGJvb2tkb3duOjpodG1sX2RvY3VtZW50MjoKICAgIGNzczogY29zbW9fY3VzdG9tLmNzcwogICAgbnVtYmVyX3NlY3Rpb25zOiB5ZXMKICAgIGNvZGVfZm9sZGluZzogc2hvdwogICAgZGZfcHJpbnQ6IGRlZmF1bHQKICAgIGZpZ19jYXB0aW9uOiB5ZXMKICAgIGNvZGVfZG93bmxvYWQ6IHllcwogICAgdG9jOiB5ZXMKICAgIHRvY19mbG9hdDoKICAgICAgY29sbGFwc2VkOiB5ZXMKICAgICAgc21vb3RoX3Njcm9sbDogbm8KbGluay1jaXRhdGlvbnM6IHllcwpwa2dkb3duOgogIGFzX2lzOiBmYWxzZQp2aWduZXR0ZTogPgogICVcVmlnbmV0dGVJbmRleEVudHJ5e05vcnRoZXJuIEVsZXBoYW50IFNlYWxzIC0gMjAxOCAoMS8yKX0KICAlXFZpZ25ldHRlRW5naW5le2tuaXRyOjpybWFya2Rvd259CiAgJVxWaWduZXR0ZUVuY29kaW5ne1VURi04fQotLS0KICAKYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9CiMgY29tbWFuZCB0byBidWlsZCBwYWNrYWdlIHdpdGhvdXQgZ2V0dGluZyB2aWduZXR0ZSBlcnJvcgojIGh0dHBzOi8vZ2l0aHViLmNvbS9yc3R1ZGlvL3JlbnYvaXNzdWVzLzgzMwojIGRldnRvb2xzOjpjaGVjayhidWlsZF9hcmdzPWMoIi0tbm8tYnVpbGQtdmlnbmV0dGVzIikpCgojIHJlZHVjZSBwbmcgc2l6ZQprbml0cjo6a25pdF9ob29rcyRzZXQob3B0aXBuZyA9IGtuaXRyOjpob29rX29wdGlwbmcpCmtuaXRyOjprbml0X2hvb2tzJHNldChwbmdxdWFudCA9IGtuaXRyOjpob29rX3BuZ3F1YW50KQoKIyBnbG9iYWwgb3B0aW9uIHJlbGF0aXZlIHRvIHJtYXJrZG93bgprbml0cjo6b3B0c19jaHVuayRzZXQoCiAgY2FjaGUgPSBGQUxTRSwKICBlY2hvID0gVFJVRSwKICBmaWcuYWxpZ24gPSAiY2VudGVyIiwKICBvdXQud2lkdGggPSAiMTAwJSIsCiAgbWVzc2FnZSA9IEZBTFNFLAogIHdhcm5pbmcgPSBGQUxTRSwKICAjIHRpZHkgPSBUUlVFLAogIGNhY2hlLmxhenkgPSBGQUxTRSwKICBvcHRpcG5nID0gIi1vNyAtcXVpZXQiLAogIHBuZ3F1YW50ID0gIi0tc3BlZWQ9MSIKKQoKIyBsaWJyYXJ5CmxpYnJhcnkoZGF0YS50YWJsZSkKbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KGthYmxlRXh0cmEpCmxpYnJhcnkobGVhZmxldCkKbGlicmFyeShndHN1bW1hcnkpCmxpYnJhcnkoY29ycnBsb3QpCmxpYnJhcnkoZ2djb3JycGxvdCkKbGlicmFyeShnZ25ld3NjYWxlKQpsaWJyYXJ5KG1hZ3JpdHRyKQpsaWJyYXJ5KERUKQpsaWJyYXJ5KHBsb3RseSkKbGlicmFyeShnZW9zcGhlcmUpCmxpYnJhcnkodGlkeW5jKQpsaWJyYXJ5KGdnYW5pbWF0ZSkKbGlicmFyeSh0cmFuc2Zvcm1yKQpsaWJyYXJ5KG1hZ2ljaykKbGlicmFyeShnaWZza2kpCmxpYnJhcnkoZ2doNHgpCgojIHJlbW92ZSBzb21lIHdhcm5pbmdzCnN1cHByZXNzV2FybmluZ3MobGlicmFyeShnZ3Bsb3QyKSkKCiMgZGVmaW5lIG15IG93biB0YWJsZSBmb3JtYXQ6IGh0dHBzOi8vZ2l0aHViLmNvbS9oYW96aHUyMzMva2FibGVFeHRyYS9pc3N1ZXMvMzc0CnNhYmxlIDwtIGZ1bmN0aW9uKHgsIGVzY2FwZSA9IFQsIC4uLikgewogIGtuaXRyOjprYWJsZSh4LCBlc2NhcGUgPSBlc2NhcGUsIC4uLikgJT4lCiAgICBrYWJsZV9zdHlsaW5nKAogICAgICBib290c3RyYXBfb3B0aW9ucyA9IGMoInN0cmlwZWQiLCAiaG92ZXIiLCAicmVzcG9uc2l2ZSIpLAogICAgICBmdWxsX3dpZHRoID0gRgogICAgKQp9CmBgYAoKVGhpcyBkb2N1bWVudCBhaW1zIGF0IGV4cGxvcmluZyB0aGUgZGF0YXNldCBvZiA0IGluZGl2aWR1YWxzIGluIDIwMTguIEZvciB0aGF0IHB1cnBvc2UsIHdlIG5lZWQgZmlyc3QgdG8gbG9hZCB0aGUgYG9udG9kaXZlYCBwYWNrYWdlIHRvIGxvYWQgZGF0YS4KCmBgYHtyIGRhdGEtZXhwbG9yYXRpb24tMjAxOC0xfQojIGxvYWQgbGlicmFyeQpsaWJyYXJ5KG9udG9kaXZlKQoKIyBsb2FkIGRhdGEKZGF0YV9uZXMgPC0gZ2V0X2RhdGEoIm5lcyIpCmBgYAoKTGV04oCZcyBoYXZlIGEgbG9vayBhdCB3aGF04oCZcyBpbnNpZGUgYGRhdGFfbmVzJGRhdGFfMjAxOGA6CiAgCmBgYHtyIGRhdGEtZXhwbG9yYXRpb24tMjAxOC0yfQojIGxpc3Qgc3RydWN0dXJlCnN0cihkYXRhX25lcyR5ZWFyXzIwMTgsIG1heC5sZXZlbCA9IDEsIGdpdmUuYXR0ciA9IEYsIG5vLmxpc3QgPSBUKQpgYGAKCj4gQSBsaXN0IG9mIGByIGxlbmd0aChkYXRhX25lcyR5ZWFyXzIwMTgpYCBgZGF0YS5mcmFtZXNgLCBvbmUgZm9yIGVhY2ggc2VhbAoKRm9yIGNvbnZlbmllbmNlLCB3ZSBhZ2dyZWdhdGUgYWxsIGByIGxlbmd0aChkYXRhX25lcyR5ZWFyXzIwMTgpYCBpbmRpdmlkdWFscyBpbnRvIG9uZSBkYXRhc2V0LgoKYGBge3IgZGF0YS1leHBsb3JhdGlvbi0yMDE4LTMsIGV2YWw9RkFMU0V9CiMgY29tYmluZSBhbGwgaW5kaXZpZHVhbHMKZGF0YV8yMDE4IDwtIHJiaW5kbGlzdChkYXRhX25lcyR5ZWFyXzIwMTgpCgojIGRpc3BsYXkKRFQ6OmRhdGF0YWJsZShkYXRhXzIwMThbc2FtcGxlLmludCguTiwgMTApLCBdLCBvcHRpb25zID0gbGlzdChzY3JvbGxYID0gVCkpCmBgYApgYGB7ciBkYXRhLWV4cGxvcmF0aW9uLTIwMTgtNCwgZWNobz1GQUxTRSwgcmVzdWx0cz0nYXNpcyd9CiMgY29tYmluZSBhbGwgaW5kaXZpZHVhbHMKZGF0YV8yMDE4IDwtIHJiaW5kbGlzdChkYXRhX25lcyR5ZWFyXzIwMTgpCgojIHRpdGxlCmNhdCgiPHRhYmxlIHN0eWxlPSd3aWR0aDogNTAlJz4iLAogIHBhc3RlMCgKICAgICI8Y2FwdGlvbj4iLAogICAgIigjdGFiOm15RFRodG1sdG9vbHMpIiwKICAgICJTYW1wbGUgb2YgMTAgcmFuZG9tIHJvd3MgZnJvbSBgZGF0YV8yMDE4YCIsCiAgICAiPC9jYXB0aW9uPiIKICApLAogICI8L3RhYmxlPiIsCiAgc2VwID0gIlxuIgopCgojIGRpc3BsYXkKRFQ6OmRhdGF0YWJsZShkYXRhXzIwMThbc2FtcGxlLmludCguTiwgMTApLCBdLCBvcHRpb25zID0gbGlzdChzY3JvbGxYID0gVCkpCmBgYAoKIyMgU3VtbWFyeQoKYGBge3IgZGF0YS1leHBsb3JhdGlvbi0yMDE4LTV9CiMgcmF3X2RhdGEKZGF0YV8yMDE4WywgLigKICBuYl9kYXlzX3JlY29yZGVkID0gdW5pcXVlTihhcy5EYXRlKGRhdGUpKSwKICBuYl9kaXZlcyA9IC5OLAogIG1heGRlcHRoX21lYW4gPSBtZWFuKG1heGRlcHRoKSwKICBkZHVyYXRpb25fbWVhbiA9IG1lYW4oZGR1cmF0aW9uKSwKICBib3R0dGltZV9tZWFuID0gbWVhbihib3R0dGltZSksCiAgcGRpX21lYW4gPSBtZWFuKHBkaSwgbmEucm0gPSBUKQopLCBieSA9IC5pZF0gJT4lCiAgc2FibGUoCiAgICBjYXB0aW9uID0gIlN1bW1hcnkgZGl2aW5nIGluZm9ybWF0aW9uIHJlbGF0aXZlIHRvIGVhY2ggMjAxOCBpbmRpdmlkdWFsIiwKICAgIGRpZ2l0cyA9IDIKICApCmBgYAo+IFZlcnkgbmljZSBkYXRhc2V0IDopCgojIyBTb21lIGV4cGxhbmF0b3J5IHBsb3RzCgojIyMgTWlzc2luZyB2YWx1ZXMKCmBgYHtyIGRhdGEtZXhwbG9yYXRpb24tMjAxOC02LCBmaWcuY2FwPSJDaGVjayBmb3IgbWlzc2luZyB2YWx1ZSBpbiAyMDE4LWluZGl2aWR1YWxzIiwgZmlnLndpZHRoPTl9CiMgYnVpbGQgZGF0YXNldCB0byBjaGVjayBmb3IgbWlzc2luZyB2YWx1ZXMKZGF0YVBsb3QgPC0gbWVsdChkYXRhXzIwMThbLCAuKC5pZCwgaXMubmEoLlNEKSksIC5TRGNvbCA9IC1jKAogICIuaWQiLAogICJkaXZlbnVtYmVyIiwKICAiZGl2ZXR5cGUiLAogICJkYXRlIiwKICAicGhhc2UiLAogICJsYXQiLAogICJsb24iCildKQojIGFkZCB0aGUgaWQgb2Ygcm93cwpkYXRhUGxvdFssIGlkX3JvdyA6PSBjKDE6Lk4pLCBieSA9IGMoInZhcmlhYmxlIiwgIi5pZCIpXQoKIyBwbG90CmdncGxvdChkYXRhUGxvdCwgYWVzKHggPSB2YXJpYWJsZSwgeSA9IGlkX3JvdywgZmlsbCA9IHZhbHVlKSkgKwogIGdlb21fdGlsZSgpICsKICBsYWJzKHggPSAiQXR0cmlidXRlcyIsIHkgPSAiUm93cyIpICsKICBzY2FsZV9maWxsX21hbnVhbCgKICAgIHZhbHVlcyA9IGMoIndoaXRlIiwgImJsYWNrIiksCiAgICBsYWJlbHMgPSBjKCJSZWFsIiwgIk1pc3NpbmciKQogICkgKwogIGZhY2V0X3dyYXAoLmlkIH4gLiwgc2NhbGVzID0gImZyZWVfeSIpICsKICB0aGVtZV9qam8oKSArCiAgdGhlbWUoCiAgICBsZWdlbmQucG9zaXRpb24gPSAidG9wIiwKICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSksCiAgICBsZWdlbmQua2V5ID0gZWxlbWVudF9yZWN0KGNvbG91ciA9ICJibGFjayIpCiAgKQpgYGAKClNvIGZhciBzbyBnb29kLCBvbmx5IGZldyB2YXJpYWJsZXMgc2VlbXMgdG8gaGF2ZSBtaXNzaW5nIHZhbHVlczoKICAKYGBge3IgZGF0YS1leHBsb3JhdGlvbi0yMDE4LTd9CiMgdGFibGUgd2l0aCBwZXJjZW50CnRhYmxlX2ludGVyIDwtIGRhdGFfMjAxOFssIGxhcHBseSguU0QsIGZ1bmN0aW9uKHgpIHsKICByb3VuZChsZW5ndGgoeFtpcy5uYSh4KV0pICogMTAwIC8gbGVuZ3RoKHgpLCAxKQp9KSwgLlNEY29sID0gLWMoCiAgIi5pZCIsCiAgImRpdmVudW1iZXIiLAogICJkaXZldHlwZSIsCiAgImRhdGUiLAogICJwaGFzZSIsCiAgImxhdCIsCiAgImxvbiIKKV0KCiMgZmluZCB3aGljaCBhcmUgZGlmZmVyZW50IGZyb20gMApjb25kX2ludGVyIDwtIHNhcHBseSh0YWJsZV9pbnRlciwgZnVuY3Rpb24oeCkgewogIHggPT0gMAp9KQoKIyBkaXNwbGF5IHRoZSBwZXJjZW50YWdlcyB0aGF0IGFyZSBvdmVyIDAKdGFibGVfaW50ZXJbLCB3aGljaChjb25kX2ludGVyKSA6PSBOVUxMXSAlPiUKICBzYWJsZShjYXB0aW9uID0gIlBlcmNlbnRhZ2Ugb2YgbWlzc2luZyB2YWx1ZXMgcGVyIGNvbHVtbnMgaGF2aW5nIG1pc3NpbmcgdmFsdWVzISIpICU+JQogIHNjcm9sbF9ib3god2lkdGggPSAiMTAwJSIpCmBgYAoKIyMjIE91dGxpZXJzIHsudGFic2V0fQoKT2ssIGxldCdzIGhhdmUgYSBsb29rIGF0IGFsbCB0aGUgZGF0YS4gQnV0IGZpcnN0LCB3ZSBoYXZlIHRvIHJlbW92ZSBvdXRsaWVycy4gU29tZSBvZiB0aGVtIGFyZSBxdWlldCBlYXN5IHRvIHNwb3QgbG9va2luZyBhdCB0aGUgZGlzdHJpYnV0aW9uIG9mIGRpdmUgZHVyYXRpb246CgojIyMjIEJlZm9yZSB7LX0KYGBge3IgZGF0YS1leHBsb3JhdGlvbi0yMDE4LTgsIGZpZy5jYXA9J0Rpc3RyaWJ1dGlvbiBvZiBgZGR1cmF0aW9uYCBmb3IgZWFjaCBzZWFsLiBUaGUgZGFzaGVkIGxpbmUgaGlnaGxpZ2h0IHRoZSAic3ViamVjdGl2ZSIgdGhyZXNob2xkIHVzZWQgdG8gcmVtb3ZlIG91dGxpZXJzICgzMDAwIHNlYyknLCBmaWcuaGVpZ2h0PTV9CmdncGxvdCgKICByYmluZCgKICAgIGNvcHkoZGF0YV8yMDE4KVssIHN0YXRlIDo9ICJCZWZvcmUiXSwKICAgIGNvcHkoZGF0YV8yMDE4KVtkZHVyYXRpb24gPCAzMDAwLCBdWywgc3RhdGUgOj0gIkFmdGVyIl0KICApICU+JQogICAgLlssIHN0YXRlIDo9IGZhY3RvcihzdGF0ZSwgbGV2ZWxzID0gYygiQmVmb3JlIiwgIkFmdGVyIikpXSwKICBhZXMoeCA9IGRkdXJhdGlvbiwgZmlsbCA9IC5pZCkKKSArCiAgZ2VvbV9oaXN0b2dyYW0oc2hvdy5sZWdlbmQgPSBGQUxTRSkgKwogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDMwMDAsIGxpbmV0eXBlID0gImxvbmdkYXNoIikgKwogIGZhY2V0X2dyaWQyKHN0YXRlIH4gLmlkLAogICAgc2NhbGVzID0gImZyZWUiLAogICAgaW5kZXBlbmRlbnQgPSAieCIKICApICsKICBsYWJzKHkgPSAiIyBvZiBkaXZlcyIsIHggPSAiRGl2ZSBkdXJhdGlvbiAocykiKSArCiAgdGhlbWVfampvKCkKYGBgCgpJdCBzZWVtcyBtdWNoIGJldHRlciwgc28gbGV0J3MgcmVtb3ZlIGFueSByb3dzIHdpdGggYGRkdXJhdGlvbmAgPiAzMDAwIHNlYy4KCmBgYHtyIGRhdGEtZXhwbG9yYXRpb24tMjAxOC0xMH0KIyBmaWx0ZXIgZGF0YQpkYXRhXzIwMThfZmlsdGVyIDwtIGRhdGFfMjAxOFtkZHVyYXRpb24gPCAzMDAwLCBdCgojIG5icm93IHJlbW92ZWQKZGF0YV8yMDE4W2RkdXJhdGlvbiA+PSAzMDAwLCAuKG5iX3Jvd19yZW1vdmVkID0gLk4pLCBieSA9IC5pZF0gJT4lCiAgc2FibGUoY2FwdGlvbiA9ICIjIG9mIHJvd3MgcmVtb3ZlZCBieSAyMDE4LWluZGl2aWR1YWxzIikKYGBgCgojIyMgQ2hlY2sgZGF5IGFuZCBuaWdodCB7LnRhYnNldH0KCiMjIyMgTGlnaHQgbGV2ZWxzCgpgYGB7ciBkYXRhLWV4cGxvcmF0aW9uLTIwMTgtMTEsIGZpZy5jYXA9IlZpc3VhbGl6YXRpb24gb2YgbGlnaHQgbGV2ZWwgYXQgdGhlIHN1cmZhY2UgYWxvbmcgMjAxOC1pbmRpdmlkdWFscycgdHJpcCIsIGZpZy5oZWlnaHQ9Nn0KIyBsZXQncyBmaXJzdCBhdmVyYWdlIGBsaWdodGF0c3VyZmAgYnkgaW5kaXZpZHVhbHMsIGRheSBzaW5jZSBkZXBhcnR1cmUgYW5kIGhvdXIKZGF0YVBsb3QgPC0gZGF0YV8yMDE4WywgLihsaWdodGF0c3VyZiA9IG1lZGlhbihsaWdodGF0c3VyZikpLAogIGJ5ID0gLiguaWQsIGRheV9kZXBhcnR1cmUsIGRhdGUgPSBhcy5EYXRlKGRhdGUpLCBob3VyID0gaG91cihkYXRlKSkKXQoKIyBkaXNwbGF5IHRoZSByZXN1bHQKZ2dwbG90KGRhdGFQbG90LCBhZXMoeCA9IGRheV9kZXBhcnR1cmUsIHkgPSBob3VyLCBmaWxsID0gbGlnaHRhdHN1cmYpKSArCiAgZ2VvbV90aWxlKCkgKwogIGZhY2V0X2dyaWQoLmlkIH4gLikgKwogIHRoZW1lX2pqbygpICsKICBsYWJzKAogICAgeCA9ICIjIG9mIGRheXMgc2luY2UgZGVwYXJ0dXJlIiwKICAgIHkgPSAiSG91ciIsCiAgICBmaWxsID0gIkxpZ2h0IGxldmVsIGF0IHRoZSBzdXJmYWNlIgogICkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9IGMoImJvdHRvbSIpKQpgYGAKCiMjIyMgRGF5IGFuZCBuaWdodCBkZXRlY3Rpb24KCmBgYHtyIGRhdGEtZXhwbG9yYXRpb24tMjAxOC0xMiwgZmlnLmNhcD0iVmlzdWFsaXphdGlvbiBvZiBkZXRlY3RlZCBuaWdodCB0aW1lIGFuZCBkYXkgdGltZSBhbG9uZyAyMDE4LWluZGl2aWR1YWxzJyB0cmlwIiwgZmlnLmhlaWdodD02fQojIGxldCdzIGZpcnN0IGF2ZXJhZ2UgYGxpZ2h0YXRzdXJmYCBieSBpbmRpdmlkdWFscywgZGF5IHNpbmNlIGRlcGFydHVyZSBhbmQgaG91cgpkYXRhUGxvdCA8LSBkYXRhXzIwMThbLCAuKGxpZ2h0YXRzdXJmID0gbWVkaWFuKGxpZ2h0YXRzdXJmKSksCiAgYnkgPSAuKC5pZCwKICAgIGRheV9kZXBhcnR1cmUsCiAgICBkYXRlID0gYXMuRGF0ZShkYXRlKSwKICAgIGhvdXIgPSBob3VyKGRhdGUpLAogICAgcGhhc2UKICApCl0KCiMgZGlzcGxheSB0aGUgcmVzdWx0CmdncGxvdChkYXRhUGxvdCwgYWVzKHggPSBkYXlfZGVwYXJ0dXJlLCB5ID0gaG91ciwgZmlsbCA9IHBoYXNlKSkgKwogIGdlb21fdGlsZSgpICsKICBmYWNldF9ncmlkKC5pZCB+IC4pICsKICB0aGVtZV9qam8oKSArCiAgbGFicygKICAgIHggPSAiIyBvZiBkYXlzIHNpbmNlIGRlcGFydHVyZSIsCiAgICB5ID0gIkhvdXIiLAogICAgZmlsbCA9ICJEYXkgdGltZSBhbmQgbmlnaHQgdGltZSBhcyBkZXRlY3RlZCBieSB0aGUgYGNhbF9waGFzZV9kYXlgIGZ1bmN0aW9uIgogICkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9IGMoImJvdHRvbSIpKQpgYGAKCiMjIyBBbGwgVmFyaWFibGVzIAoKYGBge3IgZGF0YS1leHBsb3JhdGlvbi0yMDE4LTEzfQpuYW1lc19kaXNwbGF5IDwtIG5hbWVzKGRhdGFfMjAxOF9maWx0ZXJbLCAtYygKICAiLmlkIiwKICAiZGF0ZSIsCiAgImRpdmVudW1iZXIiLAogICJkaXZldHlwZSIsCiAgImRheV9kZXBhcnR1cmUiLAogICJwaGFzZSIsCiAgImxhdCIsCiAgImxvbiIsCiAgImRpc3RfZGVwIiwKICAic3AiCildKQoKIyBjYWx1bGF0ZSB0aGUgbWVkaWFuIG9mIGRyaWZ0cmF0ZSBmb3IgZWFjaCBkYXkKbWVkaWFuX2RyaWZ0cmF0ZSA8LSBkYXRhXzIwMThbZGl2ZXR5cGUgPT0gIjI6IGRyaWZ0IiwKICAuKGRyaWZ0cmF0ZSA9IHF1YW50aWxlKGRyaWZ0cmF0ZSwgMC41KSksCiAgYnkgPSAuKGRhdGUgPSBhcy5EYXRlKGRhdGUpLCAuaWQpCl0KCiMgbGV0J3MgaWRlbnRpdHkgd2hlbiB0aGUgc21vb3RoIGNoYW5nZXMgc2lnbgpjaGFuZ2VzX2RyaWZ0cmF0ZSA8LSBtZWRpYW5fZHJpZnRyYXRlICU+JQogIC5bLCAuKAogICAgeV9zbW9vdGggPSBwcmVkaWN0KGxvZXNzKGRyaWZ0cmF0ZSB+IGFzLm51bWVyaWMoZGF0ZSksIHNwYW4gPSAwLjI1KSksCiAgICBkYXRlCiAgKSwgYnkgPSAuaWRdICU+JQogIC5bYyhGQUxTRSwgZGlmZihzaWduKHlfc21vb3RoKSkgIT0gMCksIF0KYGBgCgpgYGB7ciBkYXRhLWV4cGxvcmF0aW9uLTIwMTgtMTQsIGV2YWw9RkFMU0UsIGluY2x1ZGU9VFJVRX0KZm9yIChpIGluIG5hbWVzX2Rpc3BsYXkpIHsKICBjYXQoIiMjIyMiLCBpLCAiey51bmxpc3RlZCAudW5udW1iZXJlZH0gXG4iKQogIGlmIChpID09ICJkcmlmdHJhdGUiKSB7CiAgICBwcmludCgKICAgICAgZ2dwbG90KAogICAgICAgIGRhdGEgPSBtZWx0KGRhdGFfMjAxOF9maWx0ZXJbLCAuKC5pZCwgZGF0ZSwgZ2V0KGkpLCBkaXZldHlwZSldLAogICAgICAgICAgaWQudmFycyA9IGMoIi5pZCIsICJkYXRlIiwgImRpdmV0eXBlIikKICAgICAgICApLAogICAgICAgIGFlcygKICAgICAgICAgIHggPSBhcy5EYXRlKGRhdGUpLAogICAgICAgICAgeSA9IHZhbHVlLAogICAgICAgICAgY29sID0gZGl2ZXR5cGUKICAgICAgICApCiAgICAgICkgKwogICAgICAgIGdlb21fcG9pbnQoCiAgICAgICAgICBhbHBoYSA9IDEgLyAxMCwKICAgICAgICAgIHNpemUgPSAuNQogICAgICAgICkgKwogICAgICAgIGdlb21fdmxpbmUoCiAgICAgICAgICBkYXRhID0gY2hhbmdlc19kcmlmdHJhdGUsCiAgICAgICAgICBhZXMoeGludGVyY2VwdCA9IGRhdGUpLAogICAgICAgICAgbGluZXR5cGUgPSAyCiAgICAgICAgKSArCiAgICAgICAgZmFjZXRfd3JhcCguIH4gLmlkLCBzY2FsZXMgPSAiZnJlZSIpICsKICAgICAgICBzY2FsZV94X2RhdGUoZGF0ZV9sYWJlbHMgPSAiJW0vJVkiKSArCiAgICAgICAgbGFicyh4ID0gIkRhdGUiLCB5ID0gIkRyaWZ0IFJhdGUgJ20vcyIsIGNvbCA9ICJEaXZlIFR5cGUiKSArCiAgICAgICAgdGhlbWVfampvKCkgKwogICAgICAgIHRoZW1lKAogICAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSwKICAgICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iCiAgICAgICAgKSArCiAgICAgICAgZ3VpZGVzKGNvbG91ciA9IGd1aWRlX2xlZ2VuZChvdmVycmlkZS5hZXMgPSBsaXN0KAogICAgICAgICAgc2l6ZSA9IDcsCiAgICAgICAgICBhbHBoYSA9IDEKICAgICAgICApKSkKICAgICkKICB9IGVsc2UgewogICAgcHJpbnQoCiAgICAgIGdncGxvdCgKICAgICAgICBkYXRhID0gbWVsdChkYXRhXzIwMThfZmlsdGVyWywgLiguaWQsIGRhdGUsIGdldChpKSldLAogICAgICAgICAgaWQudmFycyA9IGMoIi5pZCIsICJkYXRlIikKICAgICAgICApLAogICAgICAgIGFlcygKICAgICAgICAgIHggPSBhcy5EYXRlKGRhdGUpLAogICAgICAgICAgeSA9IHZhbHVlLAogICAgICAgICAgY29sID0gLmlkCiAgICAgICAgKQogICAgICApICsKICAgICAgICBnZW9tX3BvaW50KAogICAgICAgICAgc2hvdy5sZWdlbmQgPSBGQUxTRSwKICAgICAgICAgIGFscGhhID0gMSAvIDEwLAogICAgICAgICAgc2l6ZSA9IC41CiAgICAgICAgKSArCiAgICAgICAgZ2VvbV92bGluZSgKICAgICAgICAgIGRhdGEgPSBjaGFuZ2VzX2RyaWZ0cmF0ZSwKICAgICAgICAgIGFlcyh4aW50ZXJjZXB0ID0gZGF0ZSksCiAgICAgICAgICBsaW5ldHlwZSA9IDIKICAgICAgICApICsKICAgICAgICBnZW9tX3ZsaW5lKGRhdGEgPSBkYXRhVmxpbmUsIGFlcyh4aW50ZXJjZXB0ID0gYXMuRGF0ZShkYXRlKSksIGNvbG91ciA9ICJibGFjayIsIGxpbmV0eXBlID0gMikgKwogICAgICAgIGZhY2V0X3dyYXAoLiB+IC5pZCwgc2NhbGVzID0gImZyZWUiKSArCiAgICAgICAgc2NhbGVfeF9kYXRlKGRhdGVfbGFiZWxzID0gIiVtLyVZIikgKwogICAgICAgIGxhYnMoeCA9ICJEYXRlIiwgeSA9IGkpICsKICAgICAgICB0aGVtZV9qam8oKSArCiAgICAgICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSkKICAgICkKICB9CgogIGNhdCgiXG4gXG4iKQp9CmBgYAoKVGhlIHZlcnRpY2FsIGRhc2hlZCBsaW5lcyByZXByZXNlbnQgY2hhbmdlcyBpbiBidW95YW5jeSAoc2VlIGB2aWduZXR0ZSgiYnVveWFuY3lfZGV0ZWN0IilgIGZvciBtb3JlIGluZm9ybWF0aW9uKQoKIyMjIHsudW5saXN0ZWQgLnVubnVtYmVyZWQgLnRhYnNldCAudGFic2V0LWZhZGUgLnRhYnNldC1waWxsc30KCmBgYHtyIGRhdGEtZXhwbG9yYXRpb24tMjAxOC0xNSwgcmVzdWx0cz0nYXNpcycsIGNhY2hlPUZBTFNFLCBlY2hvPUZBTFNFfQpmb3IgKGkgaW4gbmFtZXNfZGlzcGxheSkgewogIGNhdCgiIyMjIyIsIGksICJ7LnVubGlzdGVkIC51bm51bWJlcmVkfSBcbiIpCiAgaWYgKGkgPT0gImRyaWZ0cmF0ZSIpIHsKICAgIHByaW50KAogICAgICBnZ3Bsb3QoCiAgICAgICAgZGF0YSA9IG1lbHQoZGF0YV8yMDE4X2ZpbHRlclssIC4oLmlkLCBkYXRlLCBnZXQoaSksIGRpdmV0eXBlKV0sCiAgICAgICAgICBpZC52YXJzID0gYygiLmlkIiwgImRhdGUiLCAiZGl2ZXR5cGUiKQogICAgICAgICksCiAgICAgICAgYWVzKAogICAgICAgICAgeCA9IGFzLkRhdGUoZGF0ZSksCiAgICAgICAgICB5ID0gdmFsdWUsCiAgICAgICAgICBjb2wgPSBkaXZldHlwZQogICAgICAgICkKICAgICAgKSArCiAgICAgICAgZ2VvbV9wb2ludCgKICAgICAgICAgIGFscGhhID0gMSAvIDEwLAogICAgICAgICAgc2l6ZSA9IC41CiAgICAgICAgKSArCiAgICAgICAgZ2VvbV92bGluZSgKICAgICAgICAgIGRhdGEgPSBjaGFuZ2VzX2RyaWZ0cmF0ZSwKICAgICAgICAgIGFlcyh4aW50ZXJjZXB0ID0gZGF0ZSksCiAgICAgICAgICBsaW5ldHlwZSA9IDIKICAgICAgICApICsKICAgICAgICBmYWNldF93cmFwKC4gfiAuaWQsIHNjYWxlcyA9ICJmcmVlIikgKwogICAgICAgIHNjYWxlX3hfZGF0ZShkYXRlX2xhYmVscyA9ICIlbS8lWSIpICsKICAgICAgICBsYWJzKHggPSAiRGF0ZSIsIHkgPSAiRHJpZnQgUmF0ZSAnbS9zIiwgY29sID0gIkRpdmUgVHlwZSIpICsKICAgICAgICB0aGVtZV9qam8oKSArCiAgICAgICAgdGhlbWUoCiAgICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEpLAogICAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIKICAgICAgICApICsKICAgICAgICBndWlkZXMoY29sb3VyID0gZ3VpZGVfbGVnZW5kKG92ZXJyaWRlLmFlcyA9IGxpc3QoCiAgICAgICAgICBzaXplID0gNywKICAgICAgICAgIGFscGhhID0gMQogICAgICAgICkpKQogICAgKQogIH0gZWxzZSB7CiAgICBwcmludCgKICAgICAgZ2dwbG90KAogICAgICAgIGRhdGEgPSBtZWx0KGRhdGFfMjAxOF9maWx0ZXJbLCAuKC5pZCwgZGF0ZSwgZ2V0KGkpKV0sCiAgICAgICAgICBpZC52YXJzID0gYygiLmlkIiwgImRhdGUiKQogICAgICAgICksCiAgICAgICAgYWVzKAogICAgICAgICAgeCA9IGFzLkRhdGUoZGF0ZSksCiAgICAgICAgICB5ID0gdmFsdWUsCiAgICAgICAgICBjb2wgPSAuaWQKICAgICAgICApCiAgICAgICkgKwogICAgICAgIGdlb21fcG9pbnQoCiAgICAgICAgICBzaG93LmxlZ2VuZCA9IEZBTFNFLAogICAgICAgICAgYWxwaGEgPSAxIC8gMTAsCiAgICAgICAgICBzaXplID0gLjUKICAgICAgICApICsKICAgICAgICBnZW9tX3ZsaW5lKAogICAgICAgICAgZGF0YSA9IGNoYW5nZXNfZHJpZnRyYXRlLAogICAgICAgICAgYWVzKHhpbnRlcmNlcHQgPSBkYXRlKSwKICAgICAgICAgIGxpbmV0eXBlID0gMgogICAgICAgICkgKwogICAgICAgIGZhY2V0X3dyYXAoLiB+IC5pZCwgc2NhbGVzID0gImZyZWUiKSArCiAgICAgICAgc2NhbGVfeF9kYXRlKGRhdGVfbGFiZWxzID0gIiVtLyVZIikgKwogICAgICAgIGxhYnMoeCA9ICJEYXRlIiwgeSA9IGkpICsKICAgICAgICB0aGVtZV9qam8oKSArCiAgICAgICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSkKICAgICkKICB9CgogIGNhdCgiXG4gXG4iKQp9CmBgYAoKIyMjIHsudW5saXN0ZWQgLnVubnVtYmVyZWR9Cgo+IEZldyBxdWVzdGlvbnMsIHRoYXQgSSBzaG91bGQgbG9vayBpbnRvIGl0OgogID4KICA+ICogaXMgdGhlIGJpbW9kYWwgZGlzdHJpYnV0aW9uIG9mIGBkZHVyYXRpb25gLCBgZGVzY3RpbWVgIGR1ZSB0byBueWN0aGVtZXJhbCBtaWdyYXRpb24/CiAgPiAqIGlzIHRoZSBiaW1vZGFsIGRpc3RyaWJ1dGlvbiBvZiBgZGVzY3JhdGVgIChlc3BlY2lhbGx5IGZvciBgaW5kMjAxODA3MGAgYW5kIGBpbmRfMjAxODA3MmApIGR1ZSB0byBkcmlmdCBkaXZlPwogID4gKiBpcyBgbGlnaHRhdGJvdHRgIGNvdWxkIGJlIHVzZWQgdG8gaWRlbnRpZnkgYmlvbHVtaW5lc2NlbmNlLCBjYXVzZSBpdCBzZWVtcyB0aGVyZSBpcyBhIGxvdCBnb2luZyBvbiBhdCB0aGUgYm90dG9tPwogID4gKiBhcmUgdGhlIHZhcmlhdGlvbnMgb2JzZXJ2ZWQgZm9yIGBsaWdodGF0c3VyZmAgaXMgZHVlIHRvIG1vb24gY3ljbGU/CiAgPiAqIG5vdCBzdXJlIHdoeSBpcyB0aGVyZSBhIGJpbW9kYWwgZGlzdHJpYnV0aW9uIG9mIGB0ZW1wYXRib3R0YCEKICA+ICogYGRyaWZ0cmF0ZWAgdGhhdCBvbmUgaXMgYXdlc29tZSEgVGhhbmtzIHRvIGBkaXZldHlwZWAgd2UgY2FuIGNsZWFybHkgc2VlIGEgcGF0dGVybiBvZiBob3cgZHJpZnRyYXRlIChhbmQgc28gYnVveWFuY3kpIGNoYW5nZSBhY2NvcmRpbmcgdGltZS4KCgpgYGB7ciBkYXRhLWV4cGxvcmF0aW9uLTIwMTgtMTYsIGV2YWw9RkFMU0UsIGluY2x1ZGU9VFJVRX0KIyBzYW1lIHBsb3Qgd2l0aCBhIGNvbG9yZWQgZm9yIHRoZSBwaGFzZSBvZiB0aGUgZGF5CmZvciAoaSBpbiBuYW1lc19kaXNwbGF5KSB7CiAgY2F0KCIjIyMjIiwgaSwgInstfSBcbiIpCiAgcHJpbnQoCiAgICBnZ3Bsb3QoCiAgICAgIGRhdGEgPSBtZWx0KGRhdGFfMjAxOF9maWx0ZXJbLCAuKC5pZCwgZGF0ZSwgZ2V0KGkpLCBwaGFzZSldLAogICAgICAgIGlkLnZhcnMgPSBjKAogICAgICAgICAgIi5pZCIsCiAgICAgICAgICAiZGF0ZSIsCiAgICAgICAgICAicGhhc2UiCiAgICAgICAgKQogICAgICApLAogICAgICBhZXMoCiAgICAgICAgeCA9IGFzLkRhdGUoZGF0ZSksCiAgICAgICAgeSA9IHZhbHVlLAogICAgICAgIGNvbCA9IHBoYXNlCiAgICAgICkKICAgICkgKwogICAgICBnZW9tX3BvaW50KAogICAgICAgIGFscGhhID0gMSAvIDEwLAogICAgICAgIHNpemUgPSAuNQogICAgICApICsKICAgICAgZ2VvbV92bGluZSgKICAgICAgICBkYXRhID0gY2hhbmdlc19kcmlmdHJhdGUsCiAgICAgICAgYWVzKHhpbnRlcmNlcHQgPSBkYXRlKSwKICAgICAgICBsaW5ldHlwZSA9IDIKICAgICAgKSArCiAgICAgIGZhY2V0X3dyYXAoLiB+IC5pZCwgc2NhbGVzID0gImZyZWUiKSArCiAgICAgIHNjYWxlX3hfZGF0ZShkYXRlX2xhYmVscyA9ICIlbS8lWSIpICsKICAgICAgbGFicyh4ID0gIkRhdGUiLCB5ID0gaSkgKwogICAgICB0aGVtZV9qam8oKSArCiAgICAgIHRoZW1lKAogICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSksCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIKICAgICAgKSArCiAgICAgIGd1aWRlcyhjb2xvdXIgPSBndWlkZV9sZWdlbmQob3ZlcnJpZGUuYWVzID0gbGlzdCgKICAgICAgICBzaXplID0gNywKICAgICAgICBhbHBoYSA9IDEKICAgICAgKSkpCiAgKQogIGNhdCgiXG4gXG4iKQp9CmBgYAoKVGhlIHZlcnRpY2FsIGRhc2hlZCBsaW5lcyByZXByZXNlbnQgY2hhbmdlcyBpbiBidW95YW5jeSAoc2VlIGB2aWduZXR0ZSgiYnVveWFuY3lfZGV0ZWN0IilgIGZvciBtb3JlIGluZm9ybWF0aW9uKQoKIyMjIHsudW5saXN0ZWQgLnVubnVtYmVyZWQgLnRhYnNldCAudGFic2V0LWZhZGUgLnRhYnNldC1waWxsc30KCmBgYHtyIGRhdGEtZXhwbG9yYXRpb24tMjAxOC0xNywgcmVzdWx0cz0nYXNpcycsIGNhY2hlPUZBTFNFLCBlY2hvPUZBTFNFfQojIHNhbWUgcGxvdCB3aXRoIGEgY29sb3JlZCBmb3IgdGhlIHBoYXNlIG9mIHRoZSBkYXkKZm9yIChpIGluIG5hbWVzX2Rpc3BsYXkpIHsKICBjYXQoIiMjIyMiLCBpLCAiey19IFxuIikKICBwcmludCgKICAgIGdncGxvdCgKICAgICAgZGF0YSA9IG1lbHQoZGF0YV8yMDE4X2ZpbHRlclssIC4oLmlkLCBkYXRlLCBnZXQoaSksIHBoYXNlKV0sCiAgICAgICAgaWQudmFycyA9IGMoCiAgICAgICAgICAiLmlkIiwKICAgICAgICAgICJkYXRlIiwKICAgICAgICAgICJwaGFzZSIKICAgICAgICApCiAgICAgICksCiAgICAgIGFlcygKICAgICAgICB4ID0gYXMuRGF0ZShkYXRlKSwKICAgICAgICB5ID0gdmFsdWUsCiAgICAgICAgY29sID0gcGhhc2UKICAgICAgKQogICAgKSArCiAgICAgIGdlb21fcG9pbnQoCiAgICAgICAgYWxwaGEgPSAxIC8gMTAsCiAgICAgICAgc2l6ZSA9IC41CiAgICAgICkgKwogICAgICBnZW9tX3ZsaW5lKAogICAgICAgIGRhdGEgPSBjaGFuZ2VzX2RyaWZ0cmF0ZSwKICAgICAgICBhZXMoeGludGVyY2VwdCA9IGRhdGUpLAogICAgICAgIGxpbmV0eXBlID0gMgogICAgICApICsKICAgICAgZmFjZXRfd3JhcCguIH4gLmlkLCBzY2FsZXMgPSAiZnJlZSIpICsKICAgICAgc2NhbGVfeF9kYXRlKGRhdGVfbGFiZWxzID0gIiVtLyVZIikgKwogICAgICBsYWJzKHggPSAiRGF0ZSIsIHkgPSBpKSArCiAgICAgIHRoZW1lX2pqbygpICsKICAgICAgdGhlbWUoCiAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSwKICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIgogICAgICApICsKICAgICAgZ3VpZGVzKGNvbG91ciA9IGd1aWRlX2xlZ2VuZChvdmVycmlkZS5hZXMgPSBsaXN0KAogICAgICAgIHNpemUgPSA3LAogICAgICAgIGFscGhhID0gMQogICAgICApKSkKICApCiAgY2F0KCJcbiBcbiIpCn0KYGBgCgojIyMgQWxsIFZhcmlhYmxlcyBkdXJpbmcgdGhlIGZpcnN0IG1vbnRoCgpgYGB7ciBkYXRhLWV4cGxvcmF0aW9uLTIwMTgtMTgsIGV2YWw9RkFMU0UsIGluY2x1ZGU9VFJVRX0KZm9yIChpIGluIG5hbWVzX2Rpc3BsYXkpIHsKICBjYXQoIiMjIyMiLCBpLCAiey51bmxpc3RlZCAudW5udW1iZXJlZH0gXG4iKQogIHByaW50KAogICAgZ2dwbG90KAogICAgICBkYXRhID0gbWVsdCgKICAgICAgICBkYXRhXzIwMThfZmlsdGVyWwogICAgICAgICAgZGF5X2RlcGFydHVyZSA8IDMyLAogICAgICAgICAgLiguaWQsIGRheV9kZXBhcnR1cmUsIGdldChpKSkKICAgICAgICBdLAogICAgICAgIGlkLnZhcnMgPSBjKCIuaWQiLCAiZGF5X2RlcGFydHVyZSIpCiAgICAgICksCiAgICAgIGFlcygKICAgICAgICB4ID0gZGF5X2RlcGFydHVyZSwKICAgICAgICB5ID0gdmFsdWUsCiAgICAgICAgY29sb3IgPSAuaWQsCiAgICAgICAgZ3JvdXAgPSBkYXlfZGVwYXJ0dXJlCiAgICAgICkKICAgICkgKwogICAgICBnZW9tX2JveHBsb3QoCiAgICAgICAgc2hvdy5sZWdlbmQgPSBGQUxTRSwKICAgICAgICBhbHBoYSA9IDEgLyAxMCwKICAgICAgICBzaXplID0gLjUKICAgICAgKSArCiAgICAgIGZhY2V0X3dyYXAoLiB+IC5pZCwgc2NhbGVzID0gImZyZWUiKSArCiAgICAgIGxhYnMoeCA9ICIjIGRheXMgc2luY2UgZGVwYXJ0dXJlIiwgeSA9IGkpICsKICAgICAgdGhlbWVfampvKCkKICApCiAgY2F0KCJcbiBcbiIpCn0KYGBgCgojIyMgey51bmxpc3RlZCAudW5udW1iZXJlZCAudGFic2V0IC50YWJzZXQtZmFkZSAudGFic2V0LXBpbGxzfQoKYGBge3IgZGF0YS1leHBsb3JhdGlvbi0yMDE4LTE5LCByZXN1bHRzPSdhc2lzJywgY2FjaGU9RkFMU0UsIGVjaG89RkFMU0V9CmZvciAoaSBpbiBuYW1lc19kaXNwbGF5KSB7CiAgY2F0KCIjIyMjIiwgaSwgInsudW5saXN0ZWQgLnVubnVtYmVyZWR9IFxuIikKICBwcmludCgKICAgIGdncGxvdCgKICAgICAgZGF0YSA9IG1lbHQoCiAgICAgICAgZGF0YV8yMDE4X2ZpbHRlclsKICAgICAgICAgIGRheV9kZXBhcnR1cmUgPCAzMiwKICAgICAgICAgIC4oLmlkLCBkYXlfZGVwYXJ0dXJlLCBnZXQoaSkpCiAgICAgICAgXSwKICAgICAgICBpZC52YXJzID0gYygiLmlkIiwgImRheV9kZXBhcnR1cmUiKQogICAgICApLAogICAgICBhZXMoCiAgICAgICAgeCA9IGRheV9kZXBhcnR1cmUsCiAgICAgICAgeSA9IHZhbHVlLAogICAgICAgIGNvbG9yID0gLmlkLAogICAgICAgIGdyb3VwID0gZGF5X2RlcGFydHVyZQogICAgICApCiAgICApICsKICAgICAgZ2VvbV9ib3hwbG90KAogICAgICAgIHNob3cubGVnZW5kID0gRkFMU0UsCiAgICAgICAgYWxwaGEgPSAxIC8gMTAsCiAgICAgICAgc2l6ZSA9IC41CiAgICAgICkgKwogICAgICBmYWNldF93cmFwKC4gfiAuaWQsIHNjYWxlcyA9ICJmcmVlIikgKwogICAgICBsYWJzKHggPSAiIyBkYXlzIHNpbmNlIGRlcGFydHVyZSIsIHkgPSBpKSArCiAgICAgIHRoZW1lX2pqbygpCiAgKQogIGNhdCgiXG4gXG4iKQp9CmBgYAoKIyMjIHsudW5saXN0ZWQgLnVubnVtYmVyZWR9CgpgYGB7ciBkYXRhLWV4cGxvcmF0aW9uLTIwMTgtMjAsIGV2YWw9RkFMU0UsIGluY2x1ZGU9VFJVRX0KZm9yIChpIGluIG5hbWVzX2Rpc3BsYXkpIHsKICBjYXQoIiMjIyMiLCBpLCAiey51bmxpc3RlZCAudW5udW1iZXJlZH0gXG4iKQogIHByaW50KAogICAgZ2dwbG90KAogICAgICBkYXRhID0gbWVsdCgKICAgICAgICBkYXRhXzIwMThfZmlsdGVyWwogICAgICAgICAgZGF5X2RlcGFydHVyZSA8IDMyLAogICAgICAgICAgLiguaWQsIGRheV9kZXBhcnR1cmUsIGdldChpKSwgcGhhc2UpCiAgICAgICAgXSwKICAgICAgICBpZC52YXJzID0gYygiLmlkIiwgImRheV9kZXBhcnR1cmUiLCAicGhhc2UiKQogICAgICApLAogICAgICBhZXMoCiAgICAgICAgeCA9IGRheV9kZXBhcnR1cmUsCiAgICAgICAgeSA9IHZhbHVlLAogICAgICAgIGNvbG9yID0gcGhhc2UsCiAgICAgICAgZ3JvdXAgPSBpbnRlcmFjdGlvbihkYXlfZGVwYXJ0dXJlLCBwaGFzZSksCiAgICAgICkKICAgICkgKwogICAgICBnZW9tX2JveHBsb3QoCiAgICAgICAgYWxwaGEgPSAxIC8gMTAsCiAgICAgICAgc2l6ZSA9IC41CiAgICAgICkgKwogICAgICBmYWNldF93cmFwKC4gfiAuaWQsIHNjYWxlcyA9ICJmcmVlIikgKwogICAgICBsYWJzKHggPSAiIyBkYXlzIHNpbmNlIGRlcGFydHVyZSIsIHkgPSBpKSArCiAgICAgIHRoZW1lX2pqbygpICsKICAgICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIpCiAgKQogIGNhdCgiXG4gXG4iKQp9CmBgYAoKIyMjIHsudW5saXN0ZWQgLnVubnVtYmVyZWQgLnRhYnNldCAudGFic2V0LWZhZGUgLnRhYnNldC1waWxsc30KCmBgYHtyIGRhdGEtZXhwbG9yYXRpb24tMjAxOC0yMSwgcmVzdWx0cz0nYXNpcycsIGNhY2hlPUZBTFNFLCBlY2hvPUZBTFNFfQpmb3IgKGkgaW4gbmFtZXNfZGlzcGxheSkgewogIGNhdCgiIyMjIyIsIGksICJ7LnVubGlzdGVkIC51bm51bWJlcmVkfSBcbiIpCiAgcHJpbnQoCiAgICBnZ3Bsb3QoCiAgICAgIGRhdGEgPSBtZWx0KAogICAgICAgIGRhdGFfMjAxOF9maWx0ZXJbCiAgICAgICAgICBkYXlfZGVwYXJ0dXJlIDwgMzIsCiAgICAgICAgICAuKC5pZCwgZGF5X2RlcGFydHVyZSwgZ2V0KGkpLCBwaGFzZSkKICAgICAgICBdLAogICAgICAgIGlkLnZhcnMgPSBjKCIuaWQiLCAiZGF5X2RlcGFydHVyZSIsICJwaGFzZSIpCiAgICAgICksCiAgICAgIGFlcygKICAgICAgICB4ID0gZGF5X2RlcGFydHVyZSwKICAgICAgICB5ID0gdmFsdWUsCiAgICAgICAgY29sb3IgPSBwaGFzZSwKICAgICAgICBncm91cCA9IGludGVyYWN0aW9uKGRheV9kZXBhcnR1cmUsIHBoYXNlKSwKICAgICAgKQogICAgKSArCiAgICAgIGdlb21fYm94cGxvdCgKICAgICAgICBhbHBoYSA9IDEgLyAxMCwKICAgICAgICBzaXplID0gLjUKICAgICAgKSArCiAgICAgIGZhY2V0X3dyYXAoLiB+IC5pZCwgc2NhbGVzID0gImZyZWUiKSArCiAgICAgIGxhYnMoeCA9ICIjIGRheXMgc2luY2UgZGVwYXJ0dXJlIiwgeSA9IGkpICsKICAgICAgdGhlbWVfampvKCkgKwogICAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIikKICApCiAgY2F0KCJcbiBcbiIpCn0KYGBgCgojIyMgQ29ycmVsYXRpb24KCkNhbiB3ZSBmaW5kIG5pY2UgY29ycmVsYXRpb24/CiAgCmBgYHtyIGRhdGEtZXhwbG9yYXRpb24tMjAxOC0yMiwgZmlnLmNhcD0iQ29ycmVsYXRpb24gbWF0cml4IChjcm9zc2VzIGluZGljYXRlIG5vbiBzaWduaWZpY2FudCBjb3JyZWxhdGlvbikiLCBmaWcud2lkdGg9MTAsIGZpZy5oZWlnaHQ9MTB9CiMgY29tcHV0ZSBjb3JyZWxhdGlvbgpjb3JyXzIwMTggPC0gcm91bmQoY29yKGRhdGFfMjAxOF9maWx0ZXJbLCBuYW1lc19kaXNwbGF5LCB3aXRoID0gRl0sCiAgdXNlID0gInBhaXJ3aXNlLmNvbXBsZXRlLm9icyIKKSwgMSkKCiMgcmVwbGFjZSBOQSB2YWx1ZSBieSAwCmNvcnJfMjAxOFtpcy5uYShjb3JyXzIwMTgpXSA8LSAwCgojIGNvbXB1dGUgcF92YWx1ZXMKY29ycl9wXzIwMTggPC0gY29yX3BtYXQoZGF0YV8yMDE4X2ZpbHRlclssIG5hbWVzX2Rpc3BsYXksIHdpdGggPSBGXSkKCiMgcmVwbGFjZSBOQSB2YWx1ZSBieSAwCmNvcnJfcF8yMDE4W2lzLm5hKGNvcnJfcF8yMDE4KV0gPC0gMQoKIyBkaXNwbGF5CmdnY29ycnBsb3QoCiAgY29ycl8yMDE4LAogIHAubWF0ID0gY29ycl9wXzIwMTgsCiAgaGMub3JkZXIgPSBUUlVFLAogIG1ldGhvZCA9ICJjaXJjbGUiLAogIHR5cGUgPSAibG93ZXIiLAogIGdndGhlbWUgPSB0aGVtZV9qam8oKSwKICBzaWcubGV2ZWwgPSAwLjA1LAogIGNvbG9ycyA9IGMoIiMwMEFGQkIiLCAiI0U3QjgwMCIsICIjRkM0RTA3IikKKQpgYGAKCkFub3RoZXIgd2F5IHRvIHNlZSBpdDoKICAKYGBge3IgZGF0YS1leHBsb3JhdGlvbi0yMDE4LTIzfQojIGZsYXR0ZW4gY29ycmVsYXRpb24gbWF0cml4CmNvcl9yZXN1bHRfMjAxOCA8LSBmbGF0X2Nvcl9tYXQoY29ycl8yMDE4LCBjb3JyX3BfMjAxOCkKCiMga2VlcCBvbmx5IHRoZSBvbmUgYWJvdmUgLjcKY29yX3Jlc3VsdF8yMDE4W2NvciA+PSAuNywgXVtvcmRlcigtYWJzKGNvcikpXSAlPiUKICBzYWJsZShjYXB0aW9uID0gIlBhaXJ3aXNlIGNvcnJlbGF0aW9uIGFib3ZlIDAuNzUgYW5kIGFzc29jaWF0ZWQgcC12YWx1ZXMiKQpgYGAKCj4gSSBndWVzcyBub3RoaW5nIHVuZXhwZWN0ZWQgaGVyZSA7KQoKIyMgRGl2ZSBUeXBlCgpgYGB7ciBkYXRhLWV4cGxvcmF0aW9uLTIwMTgtMjQsIGZpZy5jYXA9IlByb3BvcnRpb24gZGl2ZSB0eXBlcyJ9CiMgZGF0YXNldCB0byBwbG90IHByb3BvcnRpb25hbCBhcmVhIHBsb3QKZGF0YVBsb3QgPC0gZGF0YV8yMDE4X2ZpbHRlciAlPiUKICAuWywgLihzdW1faWRfZGF5cyA9IC5OKSwgYnkgPSAuKC5pZCwgZGF5X2RlcGFydHVyZSwgZGl2ZXR5cGUpXSAlPiUKICAuWywgcHJvcCA6PSBzdW1faWRfZGF5cyAvIHN1bShzdW1faWRfZGF5cyksIGJ5ID0gLiguaWQsIGRheV9kZXBhcnR1cmUpXQoKIyBhcmVhIHBsb3QKZ2dwbG90KGRhdGFQbG90LCBhZXMoCiAgeCA9IGFzLm51bWVyaWMoZGF5X2RlcGFydHVyZSksCiAgeSA9IHByb3AsCiAgZmlsbCA9IGFzLmNoYXJhY3RlcihkaXZldHlwZSkKKSkgKwogIGdlb21fYXJlYShhbHBoYSA9IDAuNiwgc2l6ZSA9IDEsIHBvc2l0aW9uID0gInN0YWNrIiwgc3RhdCA9ICJpZGVudGl0eSIpICsKICBmYWNldF93cmFwKC5pZCB+IC4sIHNjYWxlcyA9ICJmcmVlIikgKwogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBzY2FsZXM6OnBlcmNlbnQpICsKICB0aGVtZV9qam8oKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIpICsKICBsYWJzKAogICAgeCA9ICIjIG9mIGRheXMgc2luY2UgZGVwYXJ0dXJlIiwKICAgIHkgPSAiUHJvcG9ydGlvbiBvZiBkaXZlcyIsCiAgICBmaWxsID0gIkRpdmUgdHlwZXMiCiAgKQpgYGAKCiMjIERpdmUgZHVyYXRpb24gKnZzLiogTWF4aW11bSBkZXB0aCB7LnRhYnNldH0KCiMjIyBDb2xvcmVkIGJ5IElECgpgYGB7ciBkYXRhLWV4cGxvcmF0aW9uLTIwMTgtMjUsIGZpZy5jYXA9IkRpdmUgZHVyYXRpb24gdnMuIE1heGltdW0gRGVwdGggY29sb3JlZCAyMDE4LWluZGl2aWR1YWxzIn0KIyBwbG90CmdncGxvdChkYXRhID0gZGF0YV8yMDE4X2ZpbHRlciwgYWVzKHkgPSBkZHVyYXRpb24sIHggPSBtYXhkZXB0aCwgY29sID0gLmlkKSkgKwogIGdlb21fcG9pbnQoc2l6ZSA9IC41LCBhbHBoYSA9IC4xLCBzaG93LmxlZ2VuZCA9IEZBTFNFKSArCiAgZmFjZXRfd3JhcCguaWQgfiAuKSArCiAgbGFicyh4ID0gIk1heGltdW0gZGVwdGggKG0pIiwgeSA9ICJEaXZlIGR1cmF0aW9uIChzKSIpICsKICB0aGVtZV9qam8oKQpgYGAKCiMjIyBDb2xvcmVkIGJ5IERpdmUgVHlwZQoKYGBge3IgZGF0YS1leHBsb3JhdGlvbi0yMDE4LTI2LCBmaWcuY2FwPSJEaXZlIGR1cmF0aW9uIHZzLiBNYXhpbXVtIERlcHRoIGNvbG9yZWQgYnkgRGl2ZSBUeXBlIn0KIyBwbG90CmdncGxvdChkYXRhID0gZGF0YV8yMDE4X2ZpbHRlciwgYWVzKAogIHkgPSBkZHVyYXRpb24sCiAgeCA9IG1heGRlcHRoLAogIGNvbCA9IGRpdmV0eXBlCikpICsKICBnZW9tX3BvaW50KHNpemUgPSAuNSwgYWxwaGEgPSAuMSkgKwogIGZhY2V0X3dyYXAoLmlkIH4gLikgKwogIGd1aWRlcyhjb2xvdXIgPSBndWlkZV9sZWdlbmQob3ZlcnJpZGUuYWVzID0gbGlzdChzaXplID0gNSwgYWxwaGEgPSAxKSkpICsKICBsYWJzKHggPSAiTWF4aW11bSBkZXB0aCAobSkiLCB5ID0gIkRpdmUgZHVyYXRpb24gKHMpIikgKwogIHRoZW1lX2pqbygpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIikKYGBgCgojIyMgQ29sb3JlZCBieSAjIGRheXMgc2luY2UgZGVwYXJ0dXJlCgpgYGB7ciBkYXRhLWV4cGxvcmF0aW9uLTIwMTgtMjcsIGZpZy5jYXA9IkRpdmUgZHVyYXRpb24gdnMuIE1heGltdW0gRGVwdGggY29sb3JlZCBieSAjIGRheXMgc2luY2UgZGVwYXJ0dXJlIn0KIyBwbG90CmdncGxvdCgKICBkYXRhID0gZGF0YV8yMDE4X2ZpbHRlclssIHByb3BfdHJhY2sgOj0gKGRheV9kZXBhcnR1cmUgKiAxMDApIC8gbWF4KGRheV9kZXBhcnR1cmUpLCBieSA9IC5pZF0sCiAgYWVzKHkgPSBkZHVyYXRpb24sIHggPSBtYXhkZXB0aCwgY29sID0gcHJvcF90cmFjaykKKSArCiAgZ2VvbV9wb2ludChzaXplID0gLjUsIGFscGhhID0gLjEpICsKICBmYWNldF93cmFwKC5pZCB+IC4pICsKICBsYWJzKAogICAgeCA9ICJNYXhpbXVtIGRlcHRoIChtKSIsCiAgICB5ID0gIkRpdmUgZHVyYXRpb24gKHMpIiwKICAgIGNvbCA9ICJQcm9wb3J0aW9uIG9mIGNvbXBsZXRlZCB0cmFjayAoJSkiCiAgKSArCiAgc2NhbGVfY29sb3JfY29udGludW91cyh0eXBlID0gInZpcmlkaXMiKSArCiAgdGhlbWVfampvKCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iKQpgYGAKCiMjIyBDb2xvcmVkIGJ5IHBoYXNlcyBvZiBkYXkKCmBgYHtyIGRhdGEtZXhwbG9yYXRpb24tMjAxOC0yOCwgZmlnLmNhcD0iRGl2ZSBkdXJhdGlvbiB2cy4gTWF4aW11bSBEZXB0aCBjb2xvcmVkIGJ5IHBoYXNlcyBvZiB0aGUgZGF5In0KIyBwbG90CmdncGxvdChkYXRhID0gZGF0YV8yMDE4X2ZpbHRlciwgYWVzKHkgPSBkZHVyYXRpb24sIHggPSBtYXhkZXB0aCwgY29sID0gcGhhc2UpKSArCiAgZ2VvbV9wb2ludChzaXplID0gLjUsIGFscGhhID0gLjEpICsKICBmYWNldF93cmFwKC5pZCB+IC4pICsKICBndWlkZXMoY29sb3VyID0gZ3VpZGVfbGVnZW5kKG92ZXJyaWRlLmFlcyA9IGxpc3Qoc2l6ZSA9IDUsIGFscGhhID0gMSkpKSArCiAgbGFicygKICAgIHggPSAiTWF4aW11bSBkZXB0aCAobSkiLAogICAgeSA9ICJEaXZlIGR1cmF0aW9uIChzKSIsCiAgICBjb2wgPSAiUGhhc2VzIG9mIHRoZSBkYXkiCiAgKSArCiAgdGhlbWVfampvKCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iKQpgYGAKCj4gVGhlcmUgc2VlbXMgdG8gYmUgYSAqcGF0Y2gqIGZvciBoaWdoIGRlcHRocyAoZXNwZWNpYWxseSB2aXNpYmxlIGZvciBgaW5kMjAxODA3MGApLCBidXQgSSBkb24ndCBrbm93IHdoYXQgaXQgY291bGQgYmUgbGlua2VkIHRvLi4uCgojIyBEcmlmdCBSYXRlCgo+IEluIHRoZSBmb2xsb3dpbmcgZ3JhcGhzOgo+Cj4gKiBgZHJpZnRyYXRlYCBpcyBjYWxjdWxhdGVkIHVzaW5nIG9ubHkgYGRpdmV0eXBlID09ICIyOiBkcmlmdCJgCj4gKiB3aGVyZWFzIGFsbCB0aGUgb3RoZXJzIHZhcmlhYmxlcyBhcmUgY2FsY3VsYXRlZCBhbGwgZGl2ZXMgY29uc2lkZXJlZAoKYGBge3IgZGF0YS1leHBsb3JhdGlvbi0yMDE4LTI5fQojIGJ1aWxkIGRhdGFzZXQKZGF0YVBsb3QgPC0gZGF0YV8yMDE4X2ZpbHRlcltkaXZldHlwZSA9PSAiMjogZHJpZnQiLAogICMgbWVkaWFuIGRyaWZ0IHJhdGUgZm9yIGRyaWZ0IGRpdmUKICAuKGRyaWZ0cmF0ZSA9IG1lZGlhbihkcmlmdHJhdGUsIG5hLnJtID0gVCkpLAogIGJ5ID0gLiguaWQsIGRheV9kZXBhcnR1cmUpCl0gJT4lCiAgLlsKICAgIGRhdGFfMjAxOF9maWx0ZXJbLAogICAgICAuKAogICAgICAgICMgbWVkaWFuIGRpdmUgZHVyYXRpb24gYWxsIGRpdmVzIGNvbnNpZGVyZWQKICAgICAgICBkZHVyYXRpb24gPSBtZWRpYW4oZGR1cmF0aW9uLCBuYS5ybSA9IFQpLAogICAgICAgICMgbWVkaWFuIG1heCBkZXB0aCBhbGwgZGl2ZXMgY29uc2lkZXJlZAogICAgICAgIG1heGRlcHRoID0gbWVkaWFuKG1heGRlcHRoLCBuYS5ybSA9IFQpLAogICAgICAgICMgbWVkaWFuIGJvdHRvbSBkaXZlcyBhbGwgZGl2ZXMgY29uc2lkZXJlZAogICAgICAgIGJvdHR0aW1lID0gbWVkaWFuKGJvdHR0aW1lLCBuYS5ybSA9IFQpCiAgICAgICksCiAgICAgIGJ5ID0gLiguaWQsIGRheV9kZXBhcnR1cmUpCiAgICBdLAogICAgb24gPSBjKCIuaWQiLCAiZGF5X2RlcGFydHVyZSIpCiAgXQpgYGAKCmBgYHtyIGRhdGEtZXhwbG9yYXRpb24tMjAxOC0zMCwgZmlnLmNhcD0iRHJpZnQgcmF0ZSB2cy4gQm90dG9tIHRpbWUifQojIHBsb3QKZ2dwbG90KGRhdGFQbG90LCBhZXMoeCA9IGJvdHR0aW1lLCB5ID0gZHJpZnRyYXRlLCBjb2wgPSAuaWQpKSArCiAgZ2VvbV9wb2ludChzaXplID0gLjUsIGFscGhhID0gLjUpICsKICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iKSArCiAgZ3VpZGVzKGNvbG9yID0gIm5vbmUiKSArCiAgZmFjZXRfd3JhcCguaWQgfiAuKSArCiAgc2NhbGVfeF9jb250aW51b3VzKGxpbWl0cyA9IGMoMCwgNzAwKSkgKwogIGxhYnMoCiAgICB4ID0gIkRhaWx5IG1lZGlhbiBCb3R0b20gdGltZSAocykiLAogICAgeSA9ICJEYWlseSBtZWRpYW4gZHJpZnQgcmF0ZSAobS5zLTEpIgogICkgKwogIHRoZW1lX2pqbygpCmBgYAoKYGBge3IgZGF0YS1leHBsb3JhdGlvbi0yMDE4LTMxLCBmaWcuY2FwPSJEcmlmdCByYXRlIHZzLiBNYXhpbXVtIGRlcHRoIn0KIyBwbG90CmdncGxvdChkYXRhUGxvdCwgYWVzKHggPSBtYXhkZXB0aCwgeSA9IGRyaWZ0cmF0ZSwgY29sID0gLmlkKSkgKwogIGdlb21fcG9pbnQoc2l6ZSA9IC41LCBhbHBoYSA9IC41KSArCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIikgKwogIGd1aWRlcyhjb2xvciA9ICJub25lIikgKwogIGZhY2V0X3dyYXAoLmlkIH4gLikgKwogIGxhYnMoCiAgICB4ID0gIkRhaWx5IG1lZGlhbiBNYXhpbXVtIGRlcHRoIChtKSIsCiAgICB5ID0gIkRhaWx5IG1lZGlhbiBkcmlmdCByYXRlIChtLnMtMSkiCiAgKSArCiAgdGhlbWVfampvKCkKYGBgCgpgYGB7ciBkYXRhLWV4cGxvcmF0aW9uLTIwMTgtMzIsIGZpZy5jYXA9IkRyaWZ0IHJhdGUgdnMuIERpdmUgZHVyYXRpb24ifQojIHBsb3QKZ2dwbG90KGRhdGFQbG90LCBhZXMoeCA9IGRkdXJhdGlvbiwgeSA9IGRyaWZ0cmF0ZSwgY29sID0gLmlkKSkgKwogIGdlb21fcG9pbnQoc2l6ZSA9IC41LCBhbHBoYSA9IC41KSArCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIikgKwogIGd1aWRlcyhjb2xvciA9ICJub25lIikgKwogIGZhY2V0X3dyYXAoLmlkIH4gLikgKwogIGxhYnMoCiAgICB4ID0gIkRhaWx5IG1lZGlhbiBEaXZlIGR1cmF0aW9uIChzKSIsCiAgICB5ID0gIkRhaWx5IG1lZGlhbiBkcmlmdCByYXRlIChtLnMtMSkiCiAgKSArCiAgdGhlbWVfampvKCkKYGBgCgojIyBCZWhhdmlvcmFsIEFlcm9iaWMgRGl2ZSBMaW1pdCAoYkFETCkKCiMjIyBbQ29vayBldCBhbCAoMjAwOCldKGh0dHBzOi8vd3d3LnNjaWVuY2VkaXJlY3QuY29tL3NjaWVuY2UvYXJ0aWNsZS9waWkvUzAwMDMzNDcyMDgwMDEzNlg/dmlhJTNEaWh1YikKCmBgYHtyIGRhdGEtZXhwbG9yYXRpb24tMjAxOC0zMywgZmlnLmNhcD0iUG9zdC1kaXZlIGR1cmF0aW9uIHZzLiBkaXZlIGR1cmF0aW9uIn0KIyBkaXZlIGR1cmF0aW9uIHZzIHBkaSBieSBkYXlzCmdncGxvdChkYXRhID0gZGF0YV8yMDE4X2ZpbHRlcltwZGkgPCAzMDAsIF0sIGFlcygKICB4ID0gZGR1cmF0aW9uLAogIHkgPSBwZGksCiAgY29sb3IgPSAuaWQsCiAgZ3JvdXAgPSBkZHVyYXRpb24sCiAgZmlsbCA9ICJub25lIgopKSArCiAgZ2VvbV9ib3hwbG90KHNob3cubGVnZW5kID0gRkFMU0UsIG91dGxpZXIuYWxwaGEgPSAwLjA1LCBhbHBoYSA9IDApICsKICBsYWJzKHggPSAiRGl2ZSBkdXJhdGlvbiAocykiLCB5ID0gIlBvc3QtZGl2ZSBkdXJhdGlvbiAocykiKSArCiAgZmFjZXRfd3JhcCguIH4gLmlkLCBzY2FsZXMgPSAiZnJlZV94IikgKwogIHRoZW1lX2pqbygpCmBgYAoKYGBge3IgZGF0YS1leHBsb3JhdGlvbi0yMDE4LTM0LCBmaWcuY2FwPSJQb3N0LWRpdmUgZHVyYXRpb24gdnMuIGRpdmUgZHVyYXRpb24gKHJhdyBkYXRhKSJ9CiMgZGl2ZSBkdXJhdGlvbiB2cyBwZGkgYnkgZGF5cwpnZ3Bsb3QoZGF0YSA9IGRhdGFfMjAxOF9maWx0ZXJbcGRpIDwgMzAwLCBdLCBhZXMoCiAgeCA9IGRkdXJhdGlvbiwKICB5ID0gcGRpLAogIGNvbG9yID0gLmlkCikpICsKICBnZW9tX3BvaW50KHNob3cubGVnZW5kID0gRkFMU0UsIGFscGhhID0gMC4wNSkgKwogIGdlb21fc21vb3RoKAogICAgbWV0aG9kID0gImdhbSIsCiAgICBzaG93LmxlZ2VuZCA9IEZBTFNFLAogICAgY29sID0gImJsYWNrIiwKICAgIGxpbmV0eXBlID0gImRhc2hlZCIKICApICsKICBsYWJzKHggPSAiRGl2ZSBkdXJhdGlvbiAocykiLCB5ID0gIlBvc3QtZGl2ZSBkdXJhdGlvbiAocykiKSArCiAgZmFjZXRfd3JhcCguIH4gLmlkLCBzY2FsZXMgPSAiZnJlZV94IikgKwogIHRoZW1lX2pqbygpCmBgYApgYGB7ciBkYXRhLWV4cGxvcmF0aW9uLTIwMTgtMzUsIGZpZy5jYXA9IlBvc3QtZGl2ZSBkdXJhdGlvbiAvIGRpdmUgZHVyYXRpb24gcmF0aW8gdnMuIGRheSBzaW5jZSBkZXBhcnR1cmUifQojIGRpdmUgZHVyYXRpb24gdnMgcGRpIGJ5IGRheXMKZ2dwbG90KAogIGRhdGEgPSBkYXRhXzIwMThfZmlsdGVyW3BkaSA8IDMwMCwgLiguaWQsIHBkaV9yYXRpbyA9IHBkaSAvIGRkdXJhdGlvbiwgZGF5X2RlcGFydHVyZSldLAogIGFlcygKICAgIHggPSBkYXlfZGVwYXJ0dXJlLAogICAgeSA9IHBkaV9yYXRpbywKICAgIGNvbG9yID0gLmlkLAogICAgZ3JvdXAgPSBkYXlfZGVwYXJ0dXJlLAogICAgZmlsbCA9ICJub25lIgogICkKKSArCiAgZ2VvbV9ib3hwbG90KAogICAgc2hvdy5sZWdlbmQgPSBGQUxTRSwKICAgIG91dGxpZXIuYWxwaGEgPSAwLjA1LAogICAgYWxwaGEgPSAwCiAgKSArCiAgbGFicyh4ID0gIiMgZGF5cyBzaW5jZSBkZXBhcnR1cmUiLCB5ID0gIlBvc3QtZGl2ZSAvIERpdmUgZHVyYXRpb24gcmF0aW8iKSArCiAgZmFjZXRfd3JhcCguIH4gLmlkLCBzY2FsZXMgPSAiZnJlZV94IikgKwogICMgem9vbQogIGNvb3JkX2NhcnRlc2lhbih5bGltID0gYygwLCAwLjQpKSArCiAgdGhlbWVfampvKCkKYGBgCgojIyMgW1NoZXJvIGV0ICphbC4qICgyMDE4KV0oaHR0cHM6Ly93d3cucmVzZWFyY2hnYXRlLm5ldC9wdWJsaWNhdGlvbi8yMjI2ODMwNDJfVG9fYnJlYXRoZV9vcl9ub3RfdG9fYnJlYXRoZV9PcHRpbWFsX2JyZWF0aGluZ19hZXJvYmljX2RpdmVfbGltaXRfYW5kX294eWdlbl9zdG9yZXNfaW5fZGVlcC1kaXZpbmdfYmx1ZS1leWVkX3NoYWdzKQoKQmFzZWQgb24gW1NoZXJvIGV0ICphbC4qICgyMDE4KV0oaHR0cHM6Ly93d3cucmVzZWFyY2hnYXRlLm5ldC9wdWJsaWNhdGlvbi8yMjI2ODMwNDJfVG9fYnJlYXRoZV9vcl9ub3RfdG9fYnJlYXRoZV9PcHRpbWFsX2JyZWF0aGluZ19hZXJvYmljX2RpdmVfbGltaXRfYW5kX294eWdlbl9zdG9yZXNfaW5fZGVlcC1kaXZpbmdfYmx1ZS1leWVkX3NoYWdzKSwgd2UgZGVjaWRlZCB0byBsb29rIGF0IHRoZSAqYkFETCogYXMgdGhlIDk1dGggcGVyY2VudGlsZSBvZiBkaXZlIGR1cmF0aW9uIGVhY2ggZGF5LCBmb3IgdGhvc2Ugd2l0aCAkbiBcZ2VxIDUwJC4gVGhpcyB0aHJlc2hvbGQgd2FzIGNob3NlbiBmb2xsb3dpbmcgdGhpcyBmaWd1cmU6CgpgYGB7ciBkYXRhLWV4cGxvcmF0aW9uLTIwMTgtMzYsIGZpZy5jYXA9IkRpc3RyaWJ1dGlvbiBvZiB0aGUgbnVtYmVyIG9mIGRpdmVzIGVhY2ggZGF5LiBUaGUgdGhyZXNob2xkIHVzZWQgdG8gY2FsY3VsYXRlIGJBREwgaXMgZml4ZWQgYXQgNTAgZGl2ZXMgcGVyIGRheS4iLCBmaWcuaGVpZ2h0PTN9CmdncGxvdCgKICBkYXRhXzIwMThfZmlsdGVyWywgLihuYl9kaXZlcyA9IC5OKSwKICAgIGJ5ID0gLiguaWQsIGRheV9kZXBhcnR1cmUpCiAgXSwKICBhZXMoeCA9IG5iX2RpdmVzLCBmaWxsID0gLmlkKQopICsKICBnZW9tX2hpc3RvZ3JhbShzaG93LmxlZ2VuZCA9IEZBTFNFKSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gNTAsIGxpbmV0eXBlID0gImRhc2hlZCIpICsKICBmYWNldF9ncmlkKC4gfiAuaWQpICsKICBsYWJzKHkgPSAiIyBvZiBkYXlzIiwgeCA9ICIjIG9mIGRpdmVzIHBlciBkYXkiKSArCiAgdGhlbWVfampvKCkKYGBgCgpgYGB7ciBkYXRhLWV4cGxvcmF0aW9uLTIwMTgtMzcsIGZpZy5jYXA9IkJlaGF2aW9yYWwgQURMIHZzLiBkcmlmdCByYXRlIGFsb25nIGFuaW1hbHMnIHRyaXAgKEFtIEkgdGhlIG9ubHkgb25lIHNlZWluZyBzb21lIGtpbmQgb2YgcmVsYXRpb25zaGlwPykifQojIHNlbGVjdCBkYXkgdGhhdCBoYXZlIGF0IGxlYXN0IDUwIGRpdmVzCmRheXNfdG9fa2VlcCA8LSBkYXRhXzIwMThfZmlsdGVyWywKICAuKG5iX2RpdmVzID0gLk4pLAogIGJ5ID0gLiguaWQsIGRheV9kZXBhcnR1cmUpCl0gJT4lCiAgLltuYl9kaXZlcyA+PSA1MCwgXQoKIyBrZWVwIG9ubHkgdGhvc2UgZGF5cwpkYXRhXzIwMThfZmlsdGVyX2NvbXBsZXRlX2RheSA8LSBtZXJnZShkYXRhXzIwMThfZmlsdGVyLAogIGRheXNfdG9fa2VlcCwKICBieSA9IGMoIi5pZCIsICJkYXlfZGVwYXJ0dXJlIikKKQoKIyBkYXRhIHBsb3QKZGF0YVBsb3QgPC0gZGF0YV8yMDE4X2ZpbHRlcl9jb21wbGV0ZV9kYXlbZGl2ZXR5cGUgPT0gIjE6IGZvcmFnaW5nIiwKICAuKGJhZGwgPSBxdWFudGlsZShkZHVyYXRpb24sIDAuOTUpKSwKICBieSA9IC4oLmlkLCBkYXlfZGVwYXJ0dXJlKQpdCgojIGNvbWJpbmUgdHdvIGRhdGFzZXRzIHRvIGJlIGFibGUgdG8gdXNlIGEgc2Vjb25kIGF4aXMKIyBodHRwczovL3N0YWNrb3ZlcmZsb3cuY29tL3F1ZXN0aW9ucy80OTE4NTU4My90d28teS1heGVzLXdpdGgtZGlmZmVyZW50LXNjYWxlcy1mb3ItdHdvLWRhdGFzZXRzLWluLWdncGxvdDIKZGF0YU1lZ2FQbG90IDwtIHJiaW5kKAogIGRhdGFfMjAxOF9maWx0ZXJfY29tcGxldGVfZGF5W2RpdmV0eXBlID09ICIyOiBkcmlmdCJdICU+JQogICAgLlssIC4oCiAgICAgIHcgPSAuaWQsCiAgICAgIHkgPSBkcmlmdHJhdGUsCiAgICAgIHggPSBkYXlfZGVwYXJ0dXJlLAogICAgICB6ID0gInNlY29uZF9wbG90IgogICAgKV0sCiAgZGF0YVBsb3RbLCAuKAogICAgdyA9IC5pZCwKICAgICMgdHJpY2t5IG9uZQogICAgeSA9IChiYWRsIC8gMTAwMCkgLSAxLAogICAgeCA9IGRheV9kZXBhcnR1cmUsCiAgICB6ID0gImZpcnN0X3Bsb3QiCiAgKV0KKQoKIyBwbG90CmdncGxvdCgpICsKICBnZW9tX3BvaW50KAogICAgZGF0YSA9IGRhdGFNZWdhUGxvdFt6ID09ICJzZWNvbmRfcGxvdCIsIF0sCiAgICBhZXMoeCA9IHgsIHkgPSB5KSwKICAgIGFscGhhID0gMSAvIDEwLAogICAgc2l6ZSA9IDAuNSwKICAgIGNvbG9yID0gImdyZXk0MCIsCiAgICBzaG93LmxlZ2VuZCA9IEZBTFNFCiAgKSArCiAgZ2VvbV9wYXRoKAogICAgZGF0YSA9IGRhdGFNZWdhUGxvdFt6ID09ICJmaXJzdF9wbG90IiwgXSwKICAgIGFlcyh4ID0geCwgeSA9IHksIGNvbG9yID0gdyksCiAgICBzaG93LmxlZ2VuZCA9IEZBTFNFCiAgKSArCiAgc2NhbGVfeV9jb250aW51b3VzKAogICAgIyBGZWF0dXJlcyBvZiB0aGUgZmlyc3QgYXhpcwogICAgbmFtZSA9ICJEcmlmdCByYXRlIChtL3MpIiwKICAgICMgQWRkIGEgc2Vjb25kIGF4aXMgYW5kIHNwZWNpZnkgaXRzIGZlYXR1cmVzCiAgICBzZWMuYXhpcyA9IHNlY19heGlzKH4gKC4gKiAxMDAwKSArIDEwMDAsCiAgICAgIG5hbWUgPSAiQmVoYXZpb3JhbCBBZXJvYmljIERpdmUgTGltaXQgKHMpIgogICAgKQogICkgKwogIGxhYnMoeCA9ICIjIGRheXMgc2luY2UgZGVwYXJ0dXJlIikgKwogIGZhY2V0X3dyYXAodyB+IC4pICsKICB0aGVtZV9qam8oKQpgYGAKCj4gTG9va2luZyBhdCB0aGlzIGdyYXBoLCBJIHdhbnQgdG8gYmVsaWV2ZSB0aGF0IHRoZXJlIGlzIHNvbWUga2luZCBvZiByZWxhdGlvbnNoaXAgYmV0d2VlbiB0aGUgKmJBREwqIGFzIGRlZmluZWQgYnkgW1NoZXJvIGV0ICphbC4qICgyMDE4KV0oaHR0cHM6Ly93d3cucmVzZWFyY2hnYXRlLm5ldC9wdWJsaWNhdGlvbi8yMjI2ODMwNDJfVG9fYnJlYXRoZV9vcl9ub3RfdG9fYnJlYXRoZV9PcHRpbWFsX2JyZWF0aGluZ19hZXJvYmljX2RpdmVfbGltaXRfYW5kX294eWdlbl9zdG9yZXNfaW5fZGVlcC1kaXZpbmdfYmx1ZS1leWVkX3NoYWdzKSBhbmQgdGhlIGRyaWZ0IHJhdGUgKGFuZCBzbyBidXlvYW5jeSkuCgpgYGB7ciBkYXRhLWV4cGxvcmF0aW9uLTIwMTgtMzh9CiMgZ2V0IGJhZGwKZGF0YXBsb3RfMSA8LSBkYXRhXzIwMThfZmlsdGVyX2NvbXBsZXRlX2RheVssCiAgLihiYWRsID0gcXVhbnRpbGUoZGR1cmF0aW9uLCAwLjk1KSksCiAgYnkgPSAuKC5pZCwgZGF5X2RlcGFydHVyZSkKXQojIGdldCBkcmlmdHJhdGUKZGF0YXBsb3RfMiA8LSBkYXRhXzIwMThfZmlsdGVyX2NvbXBsZXRlX2RheVtkaXZldHlwZSA9PSAiMjogZHJpZnQiLAogIC4oZHJpZnRyYXRlID0gbWVkaWFuKGRyaWZ0cmF0ZSkpLAogIGJ5ID0gLiguaWQsIGRheV9kZXBhcnR1cmUpCl0KCiMgbWVyZ2UKZGF0YVBsb3QgPC0gbWVyZ2UoZGF0YXBsb3RfMSwKICBkYXRhcGxvdF8yLAogIGJ5ID0gYygiLmlkIiwgImRheV9kZXBhcnR1cmUiKSwKICBhbGwgPSBUUlVFCikKCiMgcGxvdApnZ3Bsb3QoZGF0YSA9IGRhdGFQbG90LCBhZXMoeCA9IGJhZGwsIHkgPSBkcmlmdHJhdGUsIGNvbCA9IC5pZCkpICsKICBnZW9tX3BvaW50KHNob3cubGVnZW5kID0gRkFMU0UpICsKICBmYWNldF93cmFwKC5pZCB+IC4sIHNjYWxlcyA9ICJmcmVlIikgKwogIHRoZW1lX2pqbygpCmBgYAoKIyMjIHsudW5saXN0ZWQgLnVubnVtYmVyZWQgLnRhYnNldCAudGFic2V0LWZhZGUgLnRhYnNldC1waWxsc30KCiMjIyMgaW5kXzIwMTgwNzAgey51bmxpc3RlZCAudW5udW1iZXJlZH0KCmBgYHtyIGRhdGEtZXhwbG9yYXRpb24tMjAxOC0zOX0KIyBpbmRfMjAxODA3MApwbG90X2x5KAogIHggPSBkYXRhUGxvdFsuaWQgPT0gImluZF8yMDE4MDcwIiwgYmFkbF0sCiAgeSA9IGRhdGFQbG90Wy5pZCA9PSAiaW5kXzIwMTgwNzAiLCBkYXlfZGVwYXJ0dXJlXSwKICB6ID0gZGF0YVBsb3RbLmlkID09ICJpbmRfMjAxODA3MCIsIGRyaWZ0cmF0ZV0sCiAgdHlwZSA9ICJzY2F0dGVyM2QiLAogIG1vZGUgPSAibWFya2VycyIsCiAgbWFya2VyID0gbGlzdChzaXplID0gMiksCiAgY29sb3IgPSBkYXRhUGxvdFsuaWQgPT0gImluZF8yMDE4MDcwIiwgZGF5X2RlcGFydHVyZV0KKSAlPiUKICBsYXlvdXQoc2NlbmUgPSBsaXN0KAogICAgeGF4aXMgPSBsaXN0KHRpdGxlID0gIkJlaGF2aW9yYWwgQURMIiksCiAgICB5YXhpcyA9IGxpc3QodGl0bGUgPSAiIyBkYXlzIHNpbmNlIGRlcGFydHVyZSIpLAogICAgemF4aXMgPSBsaXN0KHRpdGxlID0gIkRyaWZ0IHJhdGUgKG0vcykiKQogICkpCmBgYAoKIyMjIyBpbmRfMjAxODA3MiB7LnVubGlzdGVkIC51bm51bWJlcmVkfQoKYGBge3IgZGF0YS1leHBsb3JhdGlvbi0yMDE4LTQwfQojIGluZF8yMDE4MDcyCnBsb3RfbHkoCiAgeCA9IGRhdGFQbG90Wy5pZCA9PSAiaW5kXzIwMTgwNzIiLCBiYWRsXSwKICB5ID0gZGF0YVBsb3RbLmlkID09ICJpbmRfMjAxODA3MiIsIGRheV9kZXBhcnR1cmVdLAogIHogPSBkYXRhUGxvdFsuaWQgPT0gImluZF8yMDE4MDcyIiwgZHJpZnRyYXRlXSwKICB0eXBlID0gInNjYXR0ZXIzZCIsCiAgbW9kZSA9ICJtYXJrZXJzIiwKICBtYXJrZXIgPSBsaXN0KHNpemUgPSAyKSwKICBjb2xvciA9IGRhdGFQbG90Wy5pZCA9PSAiaW5kXzIwMTgwNzIiLCBkYXlfZGVwYXJ0dXJlXQopICU+JQogIGxheW91dChzY2VuZSA9IGxpc3QoCiAgICB4YXhpcyA9IGxpc3QodGl0bGUgPSAiQmVoYXZpb3JhbCBBREwiKSwKICAgIHlheGlzID0gbGlzdCh0aXRsZSA9ICIjIGRheXMgc2luY2UgZGVwYXJ0dXJlIiksCiAgICB6YXhpcyA9IGxpc3QodGl0bGUgPSAiRHJpZnQgcmF0ZSAobS9zKSIpCiAgKSkKYGBgCgojIyMjIGluZF8yMDE4MDc0IHsudW5saXN0ZWQgLnVubnVtYmVyZWR9CgpgYGB7ciBkYXRhLWV4cGxvcmF0aW9uLTIwMTgtNDF9CiMgaW5kXzIwMTgwNzQKcGxvdF9seSgKICB4ID0gZGF0YVBsb3RbLmlkID09ICJpbmRfMjAxODA3NCIsIGJhZGxdLAogIHkgPSBkYXRhUGxvdFsuaWQgPT0gImluZF8yMDE4MDc0IiwgZGF5X2RlcGFydHVyZV0sCiAgeiA9IGRhdGFQbG90Wy5pZCA9PSAiaW5kXzIwMTgwNzQiLCBkcmlmdHJhdGVdLAogIHR5cGUgPSAic2NhdHRlcjNkIiwKICBtb2RlID0gIm1hcmtlcnMiLAogIG1hcmtlciA9IGxpc3Qoc2l6ZSA9IDIpLAogIGNvbG9yID0gZGF0YVBsb3RbLmlkID09ICJpbmRfMjAxODA3NCIsIGRheV9kZXBhcnR1cmVdCikgJT4lCiAgbGF5b3V0KHNjZW5lID0gbGlzdCgKICAgIHhheGlzID0gbGlzdCh0aXRsZSA9ICJCZWhhdmlvcmFsIEFETCIpLAogICAgeWF4aXMgPSBsaXN0KHRpdGxlID0gIiMgZGF5cyBzaW5jZSBkZXBhcnR1cmUiKSwKICAgIHpheGlzID0gbGlzdCh0aXRsZSA9ICJEcmlmdCByYXRlIChtL3MpIikKICApKQpgYGAKCiMjIyMgaW5kXzIwMTgwNzIgey51bmxpc3RlZCAudW5udW1iZXJlZH0KCmBgYHtyIGRhdGEtZXhwbG9yYXRpb24tMjAxOC00Mn0KIyBpbmRfMjAxODA4MApwbG90X2x5KAogIHggPSBkYXRhUGxvdFsuaWQgPT0gImluZF8yMDE4MDgwIiwgYmFkbF0sCiAgeSA9IGRhdGFQbG90Wy5pZCA9PSAiaW5kXzIwMTgwODAiLCBkYXlfZGVwYXJ0dXJlXSwKICB6ID0gZGF0YVBsb3RbLmlkID09ICJpbmRfMjAxODA4MCIsIGRyaWZ0cmF0ZV0sCiAgdHlwZSA9ICJzY2F0dGVyM2QiLAogIG1vZGUgPSAibWFya2VycyIsCiAgbWFya2VyID0gbGlzdChzaXplID0gMiksCiAgY29sb3IgPSBkYXRhUGxvdFsuaWQgPT0gImluZF8yMDE4MDgwIiwgZGF5X2RlcGFydHVyZV0KKSAlPiUKICBsYXlvdXQoc2NlbmUgPSBsaXN0KAogICAgeGF4aXMgPSBsaXN0KHRpdGxlID0gIkJlaGF2aW9yYWwgQURMIiksCiAgICB5YXhpcyA9IGxpc3QodGl0bGUgPSAiIyBkYXlzIHNpbmNlIGRlcGFydHVyZSIpLAogICAgemF4aXMgPSBsaXN0KHRpdGxlID0gIkRyaWZ0IHJhdGUgKG0vcykiKQogICkpCmBgYAo=